在 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();
上面的代码产生了一个奇怪的结果(我使用的是.NET 4.5编译器):
1
2
5
5
为什么价值是i
对于两个几乎相同的循环捕获不同?
在 C# 5 及更高版本中,foreach
循环声明一个separate i
循环每次迭代的变量。因此,每个闭包都会捕获一个单独的变量,并且您会看到预期的结果。
In the for
循环,你只有一个single i
变量,它被所有闭包捕获,并随着循环的进行而修改 - 因此,当您调用委托时,您会看到该单个变量的最终值。
在 C# 2、3 和 4 中,foreach
循环的行为也是如此,这基本上是never所需的行为,因此已在 C# 5 中修复。
您可以在以下位置达到相同的效果for
如果在循环体范围内引入一个新变量,则循环:
for (int i = 3; i <= 4; i++)
{
int copy = i;
actions.Add(() => Console.WriteLine(copy));
}
有关更多详细信息,请阅读 Eric Lippert 的博客文章“关闭被认为有害的循环变量”-part 1, part 2.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)