关于C#:为什么这个输出333不是在array.foreach的0112?


Why does this output 333 not 0112 at Array.ForEach?

本问题已经有最佳答案,请猛点这里访问。

为什么下面的代码ouput 333而不是012?我觉得代码太简单了,我检查,再检查,三次检查,还不能得到答案。有人能帮我吗?

1
2
3
4
5
6
7
8
9
10
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();


您应该将代码更改为:

1
2
3
4
5
6
7
8
9
10
11
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();

原因是关闭是巢

更多详细信息,请参见以下链接:是否有理由在foreach中重新使用变量c?http://ericlippert.com/2009/11/12/closing-over-the-loop-variable-considered-harmful-part-one/


这是因为原始代码中只有一个i变量,因为for没有引入一个新变量"each loop",并且同一个变量在所有闭包中都被关闭!因此,在循环之后执行任何函数之前,将为相同的(i变量分配最后一个值(3)。

与确保在每个闭包中绑定新变量的以下代码相比(这是一种罕见的情况,在这种情况下,我使用下划线表示局部变量正在发生"有趣的事情"):

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

这一行为(以及对它的抱怨)在foreach中有没有详细讨论过C重用变量的原因?-forforeach在c 4和c 5中有相同的"问题",这是c 5中foreach的"固定"问题。

I think it is fair to say that all regret that decision. This is one of the worst"gotchas" in C#, and we are going to take the breaking change to fix it. In C# 5 the foreach loop variable will be logically inside the body of the loop, and therefore closures will get a fresh copy every time. - Eric Lippert