奇怪的lambda行为

时间:2011-11-14 02:39:01

标签: c# lambda closures

我偶然发现了this article并发现它非常有趣,所以我自己进行了一些测试:

测试一:

List<Action> actions = new List<Action>();

for (int i = 0; i < 5; ++i)
    actions.Add(() => Console.WriteLine(i));

foreach (Action action in actions)
    action();

输出:

5
5
5
5
5

测试二:

List<Action> actions = new List<Action>();

for (int i = 0; i < 5; ++i)
{
    int j = i;
    actions.Add(() => Console.WriteLine(j));
}

foreach (Action action in actions)
    action();

输出:

0
1
2
3
4

根据文章,在Test One中,所有lambdas都包含对i的引用,这使得它们都输出5.这是否意味着我在测试二中得到了期望的结果因为为每个lambda表达式创建了一个新的int

3 个答案:

答案 0 :(得分:10)

这是因为C#中的 variable capturing 可能有点棘手

简而言之,for循环的每个循环都引用相同的变量 i ,因此编译器对所有循环使用相同的lambda表达式。

如果有任何安慰,这个古怪在javascript中更糟糕,因为javascript只有变量的功能范围,所以即使你的第二个解决方案也不会达到预期的效果。

This is also a very good explanation

答案 1 :(得分:7)

@Eric Lippert在他的两篇文章中详细解释了这一点:

这是一篇必读文章,因为它解释了深度和实施级别的行为。

答案 2 :(得分:1)

在Test One中,var i被捕获在循环中,但是i指的是一个有效声明一次在循环之外的变量,因此所有捕获的lambdas指的是一个变量。当您调用操作时,i的值为5,因此所有输出都为五。

在测试二中,var j被捕获在循环中,但在这种情况下j每次在>循环内声明为,因此所有捕获的lambd都引用到不同的变量。所以调用lambdas会输出不同的值。