可能重复:
Is there a reason for C#'s reuse of the variable in a foreach?
Looping through a list of Actions
今天我遇到了关于C#foreach函数的问题,它没有像我预期的那样给我正确的结果。这是代码:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int[] data = new int[] { 1, 2, 3, 4, 5 };
List<Func<int>> actions = new List<Func<int>>();
foreach (int x in data)
{
actions.Add(delegate() { return x; });
}
foreach (var foo in actions)
{
Console.WriteLine(foo());
}
Console.ReadKey();
}
}
}
当我在控制台应用程序中运行它时,它在屏幕上打印了5个。为什么?我只是无法理解。曾经问过一些人,他们只是说这个代码中有封闭,但我对此并不十分清楚,我记得在javascript中,我经常遇到封闭,但在上面的代码中,为什么会有封闭? THX。
答案 0 :(得分:6)
在C#4中,foreach
循环的所有迭代共享相同的变量,因此具有相同的闭包。
规范说:
foreach (V v in x) embedded-statement
然后扩展为:
{ E e = ((C)(x)).GetEnumerator(); try { V v; while (e.MoveNext()) { v = (V)(T)e.Current; embedded-statement } } finally { … // Dispose e } }
您可以看到在v
- 循环之外的块中声明while
,这会导致此共享行为。
这可能会在C#5中改变。
我们正在进行重大改变。在C#5中,foreach的循环变量将在逻辑上位于循环内部,因此闭包每次都会关闭变量的新副本。 “for”循环不会改变。
答案 1 :(得分:2)
关键是,当您在foreach
循环中创建委托时,您将在循环变量 x
上创建闭包,不是其当前值强>
只有当您在actions
中执行委托时,才会确定该值,即 x
当时的值。由于您已完成foreach
循环,因此该值将是data
数组中最后一项为5的项。