为啥要存储对 int (而不是值)的“引用”? [复制]

Posted

技术标签:

【中文标题】为啥要存储对 int (而不是值)的“引用”? [复制]【英文标题】:Why is "reference" to an int (and not value) stored? [duplicate]为什么要存储对 int (而不是值)的“引用”? [复制] 【发布时间】:2017-09-15 09:01:05 【问题描述】:

下面的代码sn-p会输出数字'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 循环中,并且存储了对 i 的“引用”, 而不是价值本身。因此,在我们退出循环后, 变量 i 已设置为 10,所以到每个委托时 调用时,传递给它们的值都是 10。”

我的问题是:为什么会存储对 i 的“引用”?

【问题讨论】:

【参考方案1】:

这不是按值与按引用的影响。

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

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

【讨论】:

不应该是 i 在循环外不可用 @EpicKip 是的。请参阅我在答案中链接的博客文章。 见:blogs.msdn.microsoft.com/ericlippert/2009/11/12/… & blogs.msdn.microsoft.com/ericlippert/2009/11/16/…【参考方案2】:

这是因为“在 for 循环中添加了委托,并且存储了对 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

【讨论】:

根据blogs.msdn.microsoft.com/ericlippert/2009/11/12/…用较新的C#版本,这个问题不存在了吗?

以上是关于为啥要存储对 int (而不是值)的“引用”? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥Java中BitSet的内部数据存储为long[]而不是Java中的int[]?

为啥 GOlang的float型后面要加32或64?

为啥使用 NGRX 而不是构造函数注入服务?

为啥要使用 -O2 而不是 -O3 进行编译

为啥要在 C++ 中按值传递对象 [重复]

为啥 Array.Length 是一个 int,而不是一个 uint [重复]