闭包在和foreach循环不同的行为 [英] Closures behaving differently in for and foreach loops
问题描述
在C#中的闭包我发现他们,如果他们捕获循环迭代变量,而出人意料地工作试验。
While experimenting with closures in C# I found out that they work rather unexpectedly if they capture an iterator variable in a loop.
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();
以上代码生成一个奇怪的结果(我使用.NET 4.5编译器):
The above code produces a strange result (I'm using .NET 4.5 compiler):
1
2
5
5
为什么<$ C $的C> 2几乎相同的循环不同捕捉到的值我?
推荐答案
在C#5和超越,的foreach
循环声明了的独立的为循环的每个迭代我
变量。因此,每个封捕获一个独立的变量,你可以看到预期的结果。
In C# 5 and beyond, the foreach
loop declares a separate i
variable for each iteration of the loop. So each closure captures a separate variable, and you see the expected results.
在为
循环,你只有一个的单的 I
变量,它是由所有的封闭抓获,并修改为循环的进展 - 所以,当你调用代表的时候,你看,单变量的最终值。
In the for
loop, you only have a single i
variable, which is captured by all the closures, and modified as the loop progresses - so by the time you call the delegates, you see the final value of that single variable.
在C#2,3和4,的foreach
循环表现这种方式为好,这是基本的从不的所期望的行为,所以它是固定在C#5。
In C# 2, 3 and 4, the foreach
loop behaved that way as well, which was basically never the desired behaviour, so it was fixed in C# 5.
可以达到同样的效果在为
循环,如果你介绍的循环体范围内的一个新的变量:
You can achieve the same effect in the for
loop if you introduce a new variable within the scope of the loop body:
for (int i = 3; i <= 4; i++)
{
int copy = i;
actions.Add(() => Console.WriteLine(copy));
}
有关详细信息,请阅读埃里克利珀的博客文章,关闭了循环变量有害 - 第1部分,的第2部分。
For more details, read Eric Lippert's blog posts, "Closing over the loop variable considered harmful" - part 1, part 2.
这篇关于闭包在和foreach循环不同的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!