为什么存储int(而不是值)的“引用”?

时间:2017-04-19 08:35:03

标签: c# delegates

下面的代码段将输出数字“10”十次:

delegate void Printer();

static void Main()
{
      List<Printer> printers = new List<Printer>();
      for (int i = 0; i < 10; i++)
      {
           printers.Add(delegate { Console.WriteLine(i); });
      }

      foreach (var printer in printers)
      {
           printer();
      }
}

这是因为(取自https://www.toptal.com/c-sharp/interview-questions#iquestion-90455):

  

“代表被添加到for循环中,”reference“被存储到i中,   而不是价值本身。因此,在我们退出循环后,   变量i已设置为10,因此到每个代表的时间   调用后,传递给所有这些值的值为10.“

我的问题是:为什么是“存储”的“参考”?

2 个答案:

答案 0 :(得分:4)

  

这是因为“委托被添加到for循环中,”reference“存储到i

不,这不是问题。问题是提取委托和引用值的方式。这叫做封闭。从循环中提取委托,并且只有i的最后一个值保留,因为在循环之后运行闭包。 (如果你中途调用它,它会从那个时间返回值。)

请参阅this blog post代表最终如何在看似错误的地方编译。

这是用于演示此问题的代码:

Func func1 = null;

Program.<>c__DisplayClass2 class1 = new Program.<>c__DisplayClass2(); // <-- problem

class1.i = 0;

while (class1.i < count)
{
   if (func1 == null) // <-- more problems to follow
   {
      func1 = new Func(class1.<fillFunc>b__0); // <-- yikes: just one func!
   }

   Program.funcArr[class1.i] = func1;
   class1.i++; // <-- and just one i
}

答案 1 :(得分:0)

这不是按值对参考的影响。

输出为10,因为当委托代码运行时会计算变量i的值,这是在第二个循环中,到那时它将假定值为10因为这是第一个循环退出时的结果。

使用调试器逐步调用第二个循环中对printer()的调用,您会发现委托闭包在调用时将原始作用域中的i值取为当前值。