问题描述
这工作正常(意味着预期)在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 {
actions.Add(()=> Console.WriteLine(i));
}
foreach(var act in actions)act();问题:这是我们在C#5.0之前版本中遇到的问题;所以我们不得不使用闭包的循环局部占位符,它现在是固定的 - 在C#5.0 - 在foreach循环。但不是在for循环!
这里的原因是什么(不修复
for
解决方案我会假设你的意思是
为什么不改变
循环?
答案是对于
for
循环,现有的行为是完全有道理的。如果你打破为
循环:
- 初始化
- 条件
- 迭代器
- 正文
...那么循环大致是:
{
initializer;
while(condition)
{
body;
iterator;
}
}
continue;
语句结束时执行。)
初始化部分逻辑只发生一次,因此只有一个可变实例化是完全合乎逻辑的。此外,在循环的每次迭代中,变量没有自然的初始值 - 没有什么可说的
for
循环有在初始化器中声明一个变量,在条件中测试它并在迭代器中修改它。您期望这样的循环是什么:for(int i = 0,j = 10; i {
if(someCondition)
{
j ++;
}
actions.Add(()=> Console.WriteLine(i,j));
}
与
foreach
循环,就像你为每次迭代都声明一个单独的变量一样。 heck,变量是只读的,使它甚至更多奇怪的是,它是一个变量,在迭代之间变化。认为foreach
循环在每次迭代时声明一个新的只读变量,其值取自迭代器,这是非常有意义的。This works fine (means as expected) in 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();
Prints 0 to 9. But this one shows 10 for 10 times:
var actions = new List<Action>(); for (var i = 0; i < 10; i++) { actions.Add(() => Console.WriteLine(i)); } foreach (var act in actions) act();
Question: This was a problem that we had in C# versions before 5.0; so we had to use a loop-local placeholder for the closure and it's fixed now - in C# 5.0 - in "foreach" loops. But not in "for" loops!
What is the reasoning behind this (not fixing the problem for
for
loops too)?解决方案I'm going to assume you mean "why wasn't it changed for
for
loops as well?"The answer is that for
for
loops, the existing behaviour makes perfect sense. If you break afor
loop into:
- initializer
- condition
- iterator
- body
... then the loop is roughly:
{
initializer;
while (condition)
{
body;
iterator;
}
}
(Except that the iterator
is executed at the end of a continue;
statement as well, of course.)
The initialization part logically only happens once, so it's entirely logical that there's only one "variable instantiation". Furthermore, there's no natural "initial" value of the variable on each iteration of the loop - there's nothing to say that a for
loop has to be of a form declaring a variable in the initializer, testing it in the condition and modifying it in the iterator. What would you expect a loop like this to do:
for (int i = 0, j = 10; i < j; i++)
{
if (someCondition)
{
j++;
}
actions.Add(() => Console.WriteLine(i, j));
}
Compare that with a foreach
loop which looks like you're declaring a separate variable for every iteration. Heck, the variable is read-only, making it even more odd to think of it being one variable which changes between iterations. It makes perfect sense to think of a foreach
loop as declaring a new read-only variable on each iteration with its value taken from the iterator.
这篇关于捕获闭包(循环变量)在C#5.0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!