MSDN 文档在延迟查询执行部分(强调我的)下解决了这个问题。
在返回值序列的查询中,查询变量本身从不保存查询结果,只存储查询命令。查询的执行被推迟,直到查询变量在 foreach 或 For Each 循环中被迭代...
这缩小了选项 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
某种方式还是其他方式)。具体如何发生将取决于提供者的实现。