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.