在C#5.0中捕获的闭包(循环variables)
这工作正常(意味着如预期)在C#5.0中:
var actions = new List<Action>(); foreach (var i in Enumerable.Range(0, 10)) { actions.Add(() => Console.WriteLine(i)); } foreach (var act in actions) act();
打印0到9.但是这个10次显示10次:
var actions = new List<Action>(); for (var i = 0; i < 10; i++) { actions.Add(() => Console.WriteLine(i)); } foreach (var act in actions) act();
问题:这是我们在5.0之前的C#版本中遇到的问题; 所以我们必须使用循环本地占位符来封闭,现在在C#5.0中,在“foreach”循环中已经修复了。 但不是在“for”循环中!
这背后的原因是什么(也没有解决for
循环的问题)?
这背后的推理是什么?
我会假设你的意思是“为什么不for
循环而改变呢?”
答案是for
循环,现有的行为是非常有意义的。 如果你打开一个for
循环到:
- 初始化
- 条件
- 迭代器
- 身体
…那么循环大概是:
{ initializer; while (condition) { body; iterator; } }
(当然,除了iterator
在continue;
语句结束时执行)。
初始化部分逻辑上只发生一次,所以只有一个“variables实例化”是完全合乎逻辑的。 此外,在循环的每次迭代中,variables没有自然的“初始”值 – 没有什么可以说for
循环必须是在初始化器中声明variables的forms,在条件中testing它并在迭代器。 你会期待什么循环这样做:
for (int i = 0, j = 10; i < j; i++) { if (someCondition) { j++; } actions.Add(() => Console.WriteLine(i, j)); }
将它与foreach
循环比较, 看起来像是为每个迭代声明一个单独的variables。 哎呀,这个variables是只读的, 更令人觉得奇怪的是,它是一个在迭代之间变化的variables。 将foreach
循环看作是在每次迭代中声明一个新的只读variables,并从迭代器中获取其值,这是非常有意义的。