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

查看:50
本文介绍了闭包在 for 和 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

为什么 i 的值在 2 个几乎相同的循环中的捕获方式不同?

Why is the value of i captured differently for 2 almost identical loops?

推荐答案

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

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.

for 循环中,你只有一个 single 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.

for循环中,如果在循环体的范围内引入一个新的变量,也可以达到同样的效果:

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));
}

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

For more details, read Eric Lippert's blog posts, "Closing over the loop variable considered harmful" - part 1, part 2.

这篇关于闭包在 for 和 foreach 循环中的行为不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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