score:3

Accepted answer

msdn documentation addresses this question under the deferred query execution section (emphasis mine).

in a query that returns a sequence of values, the query variable itself never holds the query results and only stores the query commands. execution of the query is deferred until the query variable is iterated over in a foreach or for each loop...

that narrows down the answer to options 2 and 3.

foreach is just syntactic sugar, underneath the compiler re-writes that as a while loop. there's a pretty thorough explanation of what happens here. basically your loop will end up looking something like this

{
  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();
  }
}

enumerator is advanced before it reaches your code inside the loop, so slightly before you get to @item.bar. that only leaves option 2, the @foreach (var item in model) line (though technically that line doesn't exist after the compiler is done with your code).

i'm not sue if the query will execute on the call to getenumerator() or on the first call to e.movenext().


as @pst points out in the comments, there are other ways to trigger execution of a query, such as by calling tolist, and it may not internally use a foreach loop. msdn documentation sort of addresses this here:

the iqueryable interface inherits the ienumerable interface so that if it represents a query, the results of that query can be enumerated. enumeration causes the expression tree associated with an iqueryable object to be executed. the definition of "executing an expression tree" is specific to a query provider. for example, it may involve translating the expression tree to an appropriate query language for the underlying data source. queries that do not return enumerable results are executed when the execute method is called.

my understanding of that is an attempt to enumerate the expression will cause it to execute (be it through a foreach or some other way). how exactly that happens will depend on the implementation of the provider.

score:-2

the work is deferred until it needs to be done. in your example, the query will run when it tries to get a value for item.

score:2

as a point of clarification, linq to sql/entity framework evaluate the linq query expressions when the getenumerator is called. this is used under the covers by foreach, thus while it appears that deferred execution waits until the foreach happens, it is actually the getenumerator that foreach uses that really is the key execution point.

score:5

the query execution (i assume getall returns iqueryable) will be deferred into the view, and will be unwrapped on the foreach line, because that is the first place where you start iterating over the collection.

update for anybody interested, here's "proof". create a class like this:

public class diagnosticcollection<t> : system.collections.generic.list<t>
{
    public new enumerator getenumerator()
    {
        debug.print("collection unwrap");
        return base.getenumerator();
    }
}

test it in your view like this:

@model playmvc.models.diagnosticcollection<string>
@{system.diagnostics.debug.print("before foreach");}
@foreach (var item in model)
{
    system.diagnostics.debug.print("after foreach");
    @item
}

Related Query

More Query from same tag