Resharper 警告的问题已在 C# 5.0 和 VB.Net 11.0 中得到解决。以下是语言规范的摘录。请注意,默认情况下,可以在安装了 Visual Studio 2012 的计算机上的以下路径中找到规范。
- C:\Program Files (x86)\Microsoft Visual Studio 11.0\VB\Specifications\1033\Visual Basic Language Specification.docx
- C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC#\Specifications\1033\CSharp Language Specification.docx
C# 语言规范版本 5.0
8.8.4 foreach 语句
v 在 while 循环中的位置对于嵌入语句中出现的任何匿名函数如何捕获它很重要。
例如:
int[] values = { 7, 9, 13 };
Action f = null;
foreach (var value in values)
{
if (f == null) f = () => Console.WriteLine("First value: " + value);
}
f();
如果 v 在 while 循环之外声明,它将在所有迭代之间共享,并且它在 for 循环之后的值将是最终值 13,这就是 f 调用将打印的值。相反,因为每次迭代都有自己的变量 v,所以在第一次迭代中被 f 捕获的变量将继续保持值 7,这就是将要打印的值。(注意:早期版本的 C# 在 while 循环之外声明了 v。)
Microsoft Visual Basic 语言规范版本 11.0
10.9.3 For Each...Next 语句(注解)
该语言的 10.0 和 11.0 版本之间的行为略有不同。在 11.0 之前,不会为循环的每次迭代创建新的迭代变量。仅当迭代变量由 lambda 或 LINQ 表达式捕获时才能观察到这种差异,然后在循环之后调用该表达式。
Dim lambdas As New List(Of Action)
For Each x In {1,2,3}
lambdas.Add(Sub() Console.WriteLine(x)
Next
lambdas(0).Invoke()
lambdas(1).Invoke()
lambdas(2).Invoke()
在 Visual Basic 10.0 之前,这会在编译时产生警告并打印 3 次“3”。这是因为只有一个变量“x”被循环的所有迭代共享,并且所有三个 lambdas 都捕获了相同的“x”,并且当 lambdas 被执行时,它就保持了数字 3。从 Visual Basic 开始11.0,它打印“1、2、3”。那是因为每个 lambda 捕获一个不同的变量“x”。