MSDNのドキュメントでは、遅延クエリ実行セクション(強調私の)でこの質問に対処しています。
一連の値を返すクエリでは、クエリ変数自体がクエリ結果を保持することはなく、クエリコマンドのみを格納します。クエリの実行は、クエリ変数がforeachまたはForEachループで繰り返されるまで延期されます...
これにより、オプション2と3の答えが絞り込まれます。
foreach
単なる構文糖衣であり、コンパイラの下でそれをwhileループとして書き直します。ここで何が起こるかについてはかなり徹底的な説明があります。基本的に、ループは次のようになります。
{
IEnumerator<?> e = ((IEnumerable<?>)Model).GetEnumerator();
try
{
int m; // this is inside the loop in C# 5
while(e.MoveNext())
{
m = (?)e.Current;
// your code goes here
}
}
finally
{
if (e != null) ((IDisposable)e).Dispose();
}
}
列挙子は、ループ内のコードに到達する前に進められるため、に到達する少し前に進みます@item.Bar
。これはオプション2の@foreach (var item in Model)
行だけを残します(ただし、技術的には、コンパイラーがコードを処理した後、その行は存在しません)。
GetEnumerator()
の呼び出しで、またはへの最初の呼び出しでクエリが実行されるかどうかはわかりませんe.MoveNext()
。
@pstがコメントで指摘しているように、クエリの実行をトリガーする方法は他にもあります。たとえば、を呼び出すなど、内部でループToList
を使用しない場合があります。foreach
MSDNドキュメントの種類はここでこれに対処します:
IQueryableインターフェイスはIEnumerableインターフェイスを継承するため、クエリを表す場合は、そのクエリの結果を列挙できます。
列挙により、IQueryableオブジェクトに関連付けられた式ツリーが実行されます。「式ツリーの実行」の定義は、クエリプロバイダーに固有です。たとえば、式ツリーを基になるデータソースの適切なクエリ言語に変換する必要がある場合があります。列挙可能な結果を返さないクエリは、Executeメソッドが呼び出されたときに実行されます。
私の理解では、式を列挙しようとすると、式が実行されます(foreach
または他の方法で)。それがどの程度正確に行われるかは、プロバイダーの実装によって異なります。