为什么我在调用Func <int>?</int>时得到错误的结果

时间:2011-03-24 15:00:40

标签: c# lambda

我在C#中有以下代码片段:

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

IEnumerable<int> values = new List<int> { 1, 2, 3 };

foreach (int value in values)
{
    actions.Add(() => value * value);
}

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

Console.ReadLine();

它运行正常,但我没有得到我期望的结果。

实际结果

9,9,9

预期结果

1,4,9

为什么我没有得到我期望的结果?

2 个答案:

答案 0 :(得分:13)

您需要捕获循环内的变量。现在,您的延迟执行操作正在使用第一个value循环中的foreach的最后一个值。

var actions = new List<Func<int>>();
        IEnumerable<int> values = new List<int> { 1, 2, 3 };
        foreach (int value in values)
        {
            var v = value;
            actions.Add(() => v * v);
        }
        foreach (var action in actions)
        {
            Console.WriteLine(action()); ;
        }
        Console.ReadLine();

请注意var v = value;行。

答案 1 :(得分:12)

您正在捕获lambda表达式中的循环变量,这意味着最终调用委托时,它会看到循环变量的 final 值。

简单修复:

foreach (int value in values)
{
    int copy = value;
    actions.Add(() => copy * copy);
}

这样在循环的每次迭代中都会得到一个新的copy变量,因此每个委托表达式将捕获一个不同的变量,并且它们不受循环变量(value)变化的影响随着时间的推移。

Eric Lippert在"Closing over the loop variable considered harmful"(以及part two)中解释了这一点。

基本上这是C#中的“陷阱”,几乎每个人都迟早会失败。