一尘不染

C#5.0中的捕获的闭包(循环变量)

c#

这在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循环问题)?


阅读 295

收藏
2020-05-19

共1个答案

一尘不染

这背后的原因是什么?

我将假设您的意思是“为什么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循环视为在每次迭代中声明一个新的只读变量(其值取自迭代器)非常有意义。

2020-05-19