闭包在和foreach循环不同的行为 [英] Closures behaving differently in for and foreach loops

查看:103
本文介绍了闭包在和foreach循环不同的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆