关于C#:为什么存储了对int(而不是value)的”引用”?

Why is “reference” to an int (and not value) stored?

本问题已经有最佳答案,请猛点这里访问。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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):

"the delegate is added in the for loop and"reference" to i is stored,
rather than the value itself. Therefore, after we exit the loop, the
variable i has been set to 10, so by the time each delegate is
invoked, the value passed to all of them is 10."

我的问题是:为什么要存储对我的"引用"?


This is because"the delegate is added in the for loop and"reference" to i is stored

不,这不是问题。问题在于如何提取委托和引用的值。这就是所谓的终结。从循环中提取委托,并且只保留EDOCX1的最后一个值(0),因为在循环之后运行闭包。(如果将其称为"中间",它将返回该时间的值)。

看看这篇博客文章,你会发现这个代表是如何在一个看似错误的地方被编译的。

这是它用来演示问题的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
}


这不是按值与参照的效果。

输出值为10,因为当委托代码运行时(在第二个循环中)会评估变量EDOCX1的值(0),到那时将假定值为10,因为这是第一个循环退出时的结果。

使用调试器在第二个循环中单步执行对printer()的调用,您会发现委托闭包在调用时的原始作用域中采用i的值。