闭包在for循环和foreach循环中表现不同

hol*_*hen 5 c# closures for-loop

在C#中尝试使用闭包时,我发现如果它们在循环中捕获迭代器变量,它们会出乎意料地工作.

var actions = new List<Action>();

foreach (int i in new[] { 1, 2 })
    actions.Add(() => Console.WriteLine(i));

for (int i = 3; i <= 4; i++)
    actions.Add(() => Console.WriteLine(i));

foreach (var action in actions)
    action();
Run Code Online (Sandbox Code Playgroud)

上面的代码产生了一个奇怪的结果(我使用的是.NET 4.5编译器):

1
2
5
5
Run Code Online (Sandbox Code Playgroud)

为什么i两个几乎相同的循环捕获的值不同?

Jon*_*eet 7

在C#5及更高版本中,foreach循环为循环的每次迭代声明一个单独的 i变量.因此每个闭包捕获一个单独的变量,您可以看到预期的结果.

for循环中,你只有一个单一的 i变量,它是由所有的封闭拍摄,并且修改循环的进展-所以你的时候调用的代表,你看,单变量的最终值.

在C#2,3和4中,foreach循环也表现出来,这基本上不是所希望的行为,因此它在C#5中得到修复.

for如果在循环体的范围内引入新变量,则可以在循环中实现相同的效果:

for (int i = 3; i <= 4; i++)
{
    int copy = i;
    actions.Add(() => Console.WriteLine(copy));
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请阅读Eric Lippert的博文,"关闭循环变量被视为有害" - 第1 部分,第2部分.