51

这在 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# 版本中遇到的问题;所以我们不得不为闭包使用循环本地占位符,现在它在“foreach”循环中已修复 - 在 C# 5.0 中。但不在“for”循环中!

这背后的原因是什么(也没有解决for循环问题)?

4

1 回答 1

47

这背后的原因是什么?

我会假设你的意思是“为什么它没有改变for循环?”

答案是对于for循环,现有的行为非常有意义。如果你把一个for循环分成:

  • 初始化器
  • (健康)状况
  • 迭代器
  • 身体

...然后循环大致是:

{
    initializer;
    while (condition)
    {
        body;
        iterator;
    }
}

(当然,除了在语句iterator末尾也执行。)continue;

初始化部分在逻辑上只发生一次,因此只有一个“变量实例化”是完全合乎逻辑的。此外,在循环的每次迭代中,变量没有自然的“初始”值 - 没有什么可以说for循环必须是在初始化程序中声明变量,在条件中测试它并在迭代器中修改它的形式. 你希望这样的循环做什么:

for (int i = 0, j = 10; i < j; i++)
{
    if (someCondition)
    {
        j++;
    }
    actions.Add(() => Console.WriteLine(i, j));
}

将其与看起来像为每次迭代声明一个单独变量的循环foreach进行比较。哎呀,该变量是只读的,因此将其视为一个在迭代之间发生变化的变量更加奇怪。将循环视为在每次迭代中声明一个新的只读变量,其值取自迭代器,这是非常有意义的。foreach

于 2013-04-28T15:19:38.613 回答