22

アイテムのリストとそれらに対する LINQ クエリがあります。さて、LINQ の遅延実行では、後続の foreach ループはクエリを 1 回だけ実行するのでしょうか、それともループ内のターンごとに実行するのでしょうか?

この例を考えると ( MSDN の Introduction to LINQ Queries (C#) から取得)

    // The Three Parts of a LINQ Query: 
    //  1. Data source. 
    int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

    // 2. Query creation. 
    // numQuery is an IEnumerable<int> 
    var numQuery =
        from num in numbers
        where (num % 2) == 0
        select num;

    // 3. Query execution. 
    foreach (int num in numQuery)
    {
        Console.Write("{0,1} ", num);
    }

または、言い換えれば、私が持っていた場合、違いはありますか:

    foreach (int num in numQuery.ToList())

また、基礎となるデータが配列ではなくデータベースにある場合は問題になるでしょうか?

4

4 に答える 4

20

さて、LINQの遅延実行では、後続のforeachループはクエリを1回だけ実行しますか、それともループ内の各ターンに対して実行しますか?

はい、ループに1回。実際には、クエリの実行は1回未満である可能性があります。途中でループを中止すると、(num % 2) == 0残りのアイテムに対してテストが実行されなくなります。

または、言い換えれば、私が持っていた場合、何か違いがありますか?

foreach (int num in numQuery.ToList())

2つの違い:

  1. 上記の場合、ToList()最初に最初と同じことを行いforeach、それからリストを作成し、次にforeachそのリストを作成するため、時間とメモリを浪費します。結果のサイズに応じて、些細なこととコードが機能しなくなることの違いがどこかにあります。

  2. ただし、同じ結果を繰り返し実行する場合、またはそれ以外の方法で繰り返し使用する場合は、クエリを1回だけ実行すると、次のクエリが再度実行されます。クエリにコストがかかる場合、このアプローチ(およびそのリストの保存)は大幅な節約になります。foreachforeachforeachToList()

于 2012-11-06T12:03:15.680 に答える
10

いいえ、違いはありません。式は1in回評価されます。より具体的には、foreachコンストラクトは式でGetEnumerator()メソッドを呼び出し、プロパティinを繰り返し呼び出しMoveNext()てアクセスし、CurrentをトラバースしIEnumerableます。

OTOH、呼び出しToList()は冗長です。わざわざ呼んではいけません。

入力がデータベースの場合、LINQ は を出力するため、状況は少し異なりますが、それでもそれを(継承する)として扱うとIQueryable確信しています。foreachIEnumerableIQueryable

于 2012-11-06T12:00:26.943 に答える
2

記述されているように、ループの各反復は、次の結果をフェッチするために必要なだけの作業を行います。したがって、答えは技術的には「上記のどれでもない」です。クエリは「分割して」実行されます。

ToList()またはその他の実体化方法 (など) を使用ToArray()すると、クエリはその場で 1 回評価され、その後の操作 (結果の反復処理など) は単純に「ダム」リストで機能します。

の代わりにnumbersがあった場合(データベースのシナリオでそうなる可能性が高い)、完全に正確な説明ではありませんが、上記は依然として真実に近いものです。特に、結果を具体化しようとする最初の試みでは、クエリ可能なプロバイダーがデータベースと対話し、結果セットを生成します。次に、この結果セットの行が反復ごとに取得されます。IQueryableIEnumerable

于 2012-11-06T12:00:36.797 に答える
1

.ToList()linq クエリは、列挙されたときに実行されます (呼び出しの結果として、または結果に対して実行されforeachます。

linq クエリの結果を 2 回列挙している場合、それ自体はIEnumerable. ただし、linq クエリによっては、常にコレクション全体を列挙するとは限りません (たとえば.Any().Single()最初のオブジェクトまたは がある場合は最初に一致するオブジェクトで停止します.Where())。

linq プロバイダーの実装の詳細は異なる場合があるため、データ ソースがデータベースである場合の通常の動作は、クエリの結果を.ToList()すぐに呼び出しcache、クエリ (EF、L2S、または NHibernate の場合) が実行されるようにすることです。コレクションがコード内のある時点で列挙されるときではなく、そこに 1 回だけ実行され、結果が複数回列挙された場合にクエリが複数回実行されるのを防ぎます。

于 2012-11-06T12:15:53.857 に答える