【问题标题】: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 的“引用”?

【问题讨论】:

    标签: c# delegates


    【解决方案1】:

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

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

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

    【讨论】:

    【解决方案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
    }
    

    【讨论】:

    猜你喜欢
    • 2012-12-20
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多