1. ホーム
  2. c#

[解決済み】IEnumerable vs List - What to Use? どのように動作するのでしょうか?

2022-04-16 09:33:45

質問

Enumeratorの動作とLINQについて疑問があります。以下の2つの単純なselectを考えてみましょう。

List<Animal> sel = (from animal in Animals 
                    join race in Species
                    on animal.SpeciesKey equals race.SpeciesKey
                    select animal).Distinct().ToList();

または

IEnumerable<Animal> sel = (from animal in Animals 
                           join race in Species
                           on animal.SpeciesKey equals race.SpeciesKey
                           select animal).Distinct();

より一般的な例として見えるように、元のオブジェクトの名前を変えてみました。クエリそのものはそれほど重要ではありません。私が聞きたいのは、これです。

foreach (Animal animal in sel) { /*do stuff*/ }

  1. を使用した場合、そのようなことはないことに気づきました。 IEnumerable この場合、IEnumerable は、いくつかの興味深いメンバーを持っています: "inner", "outer", "innerKeySelector" と "outerKeySelector", これらの最後の2つは、デリゲートのように見えます。inner"メンバには"Animal"インスタンスがなく、"Species"インスタンスがあり、とても不思議な感じがしました。outer"メンバには"Animal"インスタンスが含まれています。2つのデリゲートで、何が入って何が出てくるかを決めているのでしょうか?

  2. Distinct" を使用すると、"inner" には 6 つの項目が含まれますが (Distinct は 2 つだけなのでこれは正しくありません)、"outer" には正しい値が含まれることに気づきました。繰り返しになりますが、おそらくデリゲートメソッドがこれを決定するのでしょうが、これは私がIEnumerableについて知っていることよりも少し多いことです。

  3. 最も重要なのは、2つのオプションのうち、どちらがパフォーマンス的に優れているかということです。

による邪悪なリスト変換は .ToList() ?

あるいは、直接エニュメレータを使うとか?

できれば、このIEnumerableの使い方も少し説明するか、リンクを投げてください。

どのように解決するのですか?

IEnumerable は動作を記述し、Listはその動作の実装です。リストでは IEnumerable この場合、コンパイラに作業を後回しにする機会を与え、その過程で最適化する可能性があります。ToList()を使うと、コンパイラは結果をすぐに再定義するように強制されます。

LINQの式を積み重ねるときは、いつも IEnumerable なぜなら、動作だけを指定することで、LINQに評価を先延ばしにして、プログラムを最適化する機会を与えることができるからです。LINQはデータベースを列挙するまで、問い合わせのためのSQLを生成しないことを思い出してください。これを考えてみてください。

public IEnumerable<Animals> AllSpotted()
{
    return from a in Zoo.Animals
           where a.coat.HasSpots == true
           select a;
}

public IEnumerable<Animals> Feline(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Felidae"
           select a;
}

public IEnumerable<Animals> Canine(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Canidae"
           select a;
}

これで、初期サンプル ("AllSpotted") を選択するメソッドと、いくつかのフィルタができました。これで、こんなことができるようになりました。

var Leopards = Feline(AllSpotted());
var Hyenas = Canine(AllSpotted());

では、List を使用した方が速いかというと IEnumerable ? クエリが複数回実行されるのを防ぎたい場合のみです。しかし、全体として見れば、その方が良いのでしょうか?上の例では、Leopard と Hyenas が それぞれ単一のSQLクエリ そして、データベースは関連する行だけを返します。しかし、もし AllSpotted() というのも、データベースは実際に必要なデータよりもはるかに多くのデータを返す可能性があり、クライアントでフィルタリングを行うサイクルを浪費してしまうからです。

プログラムでは、クエリをリストに変換するのを最後まで遅らせたほうがいい場合があります。レオパードやハイエナを何度も列挙する場合は、こうします。

List<Animals> Leopards = Feline(AllSpotted()).ToList();
List<Animals> Hyenas = Canine(AllSpotted()).ToList();