7

MVCビューに返される非常に基本的なLINQを考えると、遅延実行はどの正確な時点で発生しますか?

コントローラ内:

public ActionResult Index()
{
    var model = _fooService.GetAll();
    return View(model);
}

モデル内:

@foreach (var item in Model) {    
    <tr>
        <td>@item.Bar</td>
   </tr>
}

もちろん、呼び出し時にはクエリは実行されません_fooService.GetAll()が、後の時点まで延期されますが、正確にはどの時点で実行されますか?

  • コントローラのreturn View(model);ステートメント(そのようには見えません)?
  • ビューの@foreach (var item in Model)線?
  • ビューの線が初めて@item.Barヒットしたときは?
  • return View(model);レンダリングされているビューとの間に発生する他の何か?
4

4 に答える 4

5

クエリの実行(GetAllはiqueryableを返すと思います)はビューに延期され、コレクションの反復を開始する最初の場所であるため、foreach行でラップ解除されます。

更新 興味のある人のために、ここに「証拠」があります。次のようなクラスを作成します。

public class DiagnosticCollection<T> : System.Collections.Generic.List<T>
{
    public new Enumerator GetEnumerator()
    {
        Debug.Print("Collection Unwrap");
        return base.GetEnumerator();
    }
}

次のようにビューでテストします。

@model PlayMvc.Models.DiagnosticCollection<string>
@{System.Diagnostics.Debug.Print("Before foreach");}
@foreach (var item in Model)
{
    System.Diagnostics.Debug.Print("After foreach");
    @item
}
于 2012-10-29T02:09:37.040 に答える
3

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を使用しない場合があります。foreachMSDNドキュメントの種類はここでこれに対処します:

IQueryableインターフェイスはIEnumerableインターフェイスを継承するため、クエリを表す場合は、そのクエリの結果を列挙できます。 列挙により、IQueryableオブジェクトに関連付けられた式ツリーが実行されます。「式ツリーの実行」の定義は、クエリプロバイダーに固有です。たとえば、式ツリーを基になるデータソースの適切なクエリ言語に変換する必要がある場合があります。列挙可能な結果を​​返さないクエリは、Executeメソッドが呼び出されたときに実行されます。

私の理解では、式を列挙しようとすると、式が実行されます(foreachまたは他の方法で)。それがどの程度正確に行われるかは、プロバイダーの実装によって異なります。

于 2012-10-29T04:25:42.360 に答える
2

明確にするために、LINQ to SQL / Entity Frameworkは、GetEnumeratorが呼び出されたときにLINQクエリ式を評価します。これはforeachの内部で使用されるため、遅延実行はforeachが発生するまで待機しているように見えますが、実際に重要な実行ポイントはforeachが使用するGetEnumeratorです。

于 2012-10-29T15:46:46.023 に答える
-2

作業は、実行する必要があるまで延期されます。この例では、クエリは。の値を取得しようとしたときに実行されますitem

于 2012-10-29T04:05:56.647 に答える