你如何捕获迭代变量?

Asa*_*Ali 12 .net c# lambda for-loop

捕获for循环的迭代变量时,C#将该变量视为在循环外声明.这意味着在每次迭代中捕获相同的变量.以下程序写入333而不是写入012:

Action[] actions = new Action[3];
for (int i = 0; i < 3; i++)
    actions [i] = () => Console.Write (i);

foreach (Action a in actions) a(); // 333
Run Code Online (Sandbox Code Playgroud)

我在Nutshell(第5版)中阅读C#,今天我遇到了这个,但我无法理解它,我不知道输出是什么333而不是012.是因为i打印的值是循环的值吗?怎么可能?i应该在循环后处理,不是吗?

Dav*_*idG 10

变量i是在for循环中捕获的,但是你可以通过这样做来扩展它的范围.所以变量保留在它的最后状态3,因此代码输出333.

编写代码的另一种方法是:

Action[] actions = new Action[3];
int i; //declare i here instead of in the for loop

for (i = 0; i < 3; i++)
    actions [i] = () => Console.Write (i);

//Now i=3
foreach (Action a in actions) a(); // 333
Run Code Online (Sandbox Code Playgroud)

输出与写入相同:

Console.Write(i);
Console.Write(i);
Console.Write(i);
Run Code Online (Sandbox Code Playgroud)

  • 请注意,自从C#5以来,`foreach`已被修复为*not*将`i`放在循环外部,但在内部.换句话说,如果你将循环更改为:`foreach(int in Enumerable.Range(0,3))`,你实际上会得到`012`.但是,该修复不适用于`for`. (8认同)

Sel*_*enç 6

因为lambda捕获了最后一个值i,也就是3你的循环的.step被执行了最后一次,然后我变成了3你的循环结束.

我想这会让你清楚:

int i = 0;
for (; i < 3; i++) { }

Console.WriteLine(i);  // writes 3
Run Code Online (Sandbox Code Playgroud)

您可以使用临时变量来解决此问题:

for (int i = 0; i < 3; i++)
{
    int temp = i;
    actions[i] = () => Console.Write(temp);
}

foreach (Action a in actions) a(); // now: 012
Run Code Online (Sandbox Code Playgroud)

我建议你阅读这篇文章,以更好地理解闭包