奇怪的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会输出不同的值。