我遇到了一个关于c#的有趣问题。我有如下代码。

List<Func<int>> actions = new List<Func<int>>();

int variable = 0;
while (variable < 5)
{
    actions.Add(() => variable * 2);
    ++ variable;
}

foreach (var act in actions)
{
    Console.WriteLine(act.Invoke());
}

我期望它输出0 2 4 6 8。然而,它实际上输出了5个10。

这似乎是由于所有的操作都指向一个捕获的变量。因此,当调用它们时,它们都有相同的输出。

有没有办法绕过这个限制,让每个动作实例都有自己的捕获变量?


当前回答

它被称为闭合问题, 只需使用一个复制变量,就完成了。

List<Func<int>> actions = new List<Func<int>>();

int variable = 0;
while (variable < 5)
{
    int i = variable;
    actions.Add(() => i * 2);
    ++ variable;
}

foreach (var act in actions)
{
    Console.WriteLine(act.Invoke());
}

其他回答

解决这个问题的方法是将需要的值存储在代理变量中,并捕获该变量。

I.E.

while( variable < 5 )
{
    int copy = variable;
    actions.Add( () => copy * 2 );
    ++variable;
}

是的,你需要在循环内的作用域变量,并通过这种方式传递给lambda:

List<Func<int>> actions = new List<Func<int>>();

int variable = 0;
while (variable < 5)
{
    int variable1 = variable;
    actions.Add(() => variable1 * 2);
    ++variable;
}

foreach (var act in actions)
{
    Console.WriteLine(act.Invoke());
}

Console.ReadLine();

它被称为闭合问题, 只需使用一个复制变量,就完成了。

List<Func<int>> actions = new List<Func<int>>();

int variable = 0;
while (variable < 5)
{
    int i = variable;
    actions.Add(() => i * 2);
    ++ variable;
}

foreach (var act in actions)
{
    Console.WriteLine(act.Invoke());
}
for (int n=0; n < 10; n++) //forloop syntax
foreach (string item in foo) foreach syntax

我相信你正在经历的是所谓的关闭http://en.wikipedia.org/wiki/Closure_(computer_science)。你的lamba有一个对变量的引用,这个变量的作用域在函数本身之外。你的lamba直到你调用它才被解释,一旦它被解释,它将在执行时得到变量的值。