在C#中使用lambda表达式或匿名方法时,我们必须小心访问修改的闭包陷阱。例如:

foreach (var s in strings)
{
   query = query.Where(i => i.Prop == s); // access to modified closure
   ...
}

由于修改了闭包,上述代码将导致查询中的所有Where子句都基于s的最终值。

正如这里所解释的,这是因为上面foreach循环中声明的s变量在编译器中被这样翻译:

string s;
while (enumerator.MoveNext())
{
   s = enumerator.Current;
   ...
}

而不是像这样:

while (enumerator.MoveNext())
{
   string s;
   s = enumerator.Current;
   ...
}

正如这里所指出的,在循环外声明变量没有性能优势,在正常情况下,我能想到的唯一原因是如果您计划在循环范围外使用变量:

string s;
while (enumerator.MoveNext())
{
   s = enumerator.Current;
   ...
}
var finalString = s;

但是,foreach循环中定义的变量不能在循环外使用:

foreach(string s in strings)
{
}
var finalString = s; // won't work: you're outside the scope.

因此,编译器声明变量的方式使其很容易发生错误,而错误通常很难发现和调试,同时不会产生明显的好处。

如果foreach循环是用内部作用域变量编译的,那么您是否可以用这种方式处理它们,或者这只是在匿名方法和lambda表达式可用或通用之前所做的任意选择,并且从那时起就没有修改过?