奇怪的lambda行为

tbr*_*dge 11 c# lambda closures

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

测试一:

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

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

foreach (Action action in actions)
    action();
Run Code Online (Sandbox Code Playgroud)

输出:

5
5
5
5
5
Run Code Online (Sandbox Code Playgroud)

测试二:

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();
Run Code Online (Sandbox Code Playgroud)

输出:

0
1
2
3
4
Run Code Online (Sandbox Code Playgroud)

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

par*_*mar 10

这是因为C#中的变量捕获可能有点棘手

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

如果它是任何安慰,这种奇怪性在javascript中更糟,因为javascript只有变量的函数范围,所以即使你的第二个解决方案也不会做你期望的.

这也是一个很好的解释


Naw*_*waz 7

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

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