奇怪的lambda行为

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

测试一:

List actions = new List(); for (int i = 0; i  Console.WriteLine(i)); foreach (Action action in actions) action(); 

输出:

 5 5 5 5 5 

测试二:

 List actions = new List(); for (int i = 0; i  Console.WriteLine(j)); } foreach (Action action in actions) action(); 

输出:

 0 1 2 3 4 

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

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

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

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

这也是一个很好的解释

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

  • 关闭循环变量被认为是有害的
  • 关闭循环变量,第二部分

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

是。

在Test One中,var i被捕获在循环中,但是i指的是在循环外部有效声明的变量,因此所有捕获的lambd都引用一个变量 。 当你调用动作时, i值为5因此所有输出都是5。

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