在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表达式可用或常见之前做出的,从那时起就没有修改过?