在C#中使用lambda表达式或匿名方法时,我们必须警惕对修改后的闭包陷阱的访问。例如:
foreach (var s in strings)
{
query = query.Where(i => i.Prop == s); // access to modified closure
...
}
由于修改了闭包,因此上述代码将导致Where
查询中的所有子句都基于的最终值s
。
正如解释在这里,这是因为该s
变量在声明foreach
环以上的编译器编译如下:
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表达式可用或通用之前做出的任意选择,并且没有从那以后就没有修改过?
foreach
而是关于lamda表达式,其结果类似于OP所示的代码...
String s; foreach (s in strings) { ... }
?