为什么在Array.ForEach中输出333不是0112?

时间:2014-05-03 02:01:57

标签: c#

为什么下面的代码输出333不是012? 我认为代码是如此简单,我检查和检查,仔细检查,三重检查,还不能得到答案。任何人都可以帮助我吗?

Action[] tmp = new Action[3];

for (int i = 0; i < tmp.Length; i++)
{
    tmp[i] = () => Console.WriteLine(i);
}

Array.ForEach(tmp, m => m());

Console.Read();

2 个答案:

答案 0 :(得分:1)

这是因为原始代码中只有一个 i变量,因为for 引入新变量&#34;每个循环&#34;并且相同的变量在所有闭包中被关闭!因此,在循环之后执行任何函数之前,相同的i)变量被赋予最后一个值(3)。

与下面的代码比较,确保在每个闭包中绑定 new 变量(这是一种罕见的情况,我使用下划线表示局部变量&#34;有趣的东西&#34;正在发生):

for (int _i = 0; _i < tmp.Length; _i++)
{
    int i = _i; // NEW/fresh variable, i, introduced each loop
    tmp[i] = () => Console.WriteLine(i);
}

Is there a reason for C#'s reuse of the variable in a foreach? - for中详细讨论了这种行为(和投诉),foreach也有同样的问题&#34;在C#4和之前,这是&#34;固定&#34;对于C#5中的foreach

  

我认为可以公平地说这一切都让人感到后悔。这是最糟糕的&#34;陷阱之一&#34;在C#中,我们将采取重大改变来解决它。在C#5中,foreach循环变量将在逻辑上位于循环体内,因此闭包每次都会得到一个新的副本。 - Eric Lippert

答案 1 :(得分:1)

您应该将代码更改为:

Action[] tmp = new Action[3];

for (int i = 0; i < tmp.Length; i++)
{
    int j = i;
    tmp[i] = () => Console.WriteLine(j);
}

Array.ForEach(tmp, m => m());

Console.Read();

原因是封闭是巢

更详细的信息请看这些链接: Is there a reason for C#'s reuse of the variable in a foreach? http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/