2017-04-19 45 views
0

下面将输出的代码片段数“10”十倍:为什么“引用”一个int(而不是值)存储?

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已被设置为10,因此在调用每个代表 时,传递给它们的值均为10 “。

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

回答

0

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

的输出是10,因为当代表代码运行,这是在第二循环中,并且通过时间会假设的10值可变i的值被评估,因为这是它与时结束第一个循环退出。

使用调试器在第二个循环中逐步调用printer(),您会发现委托关闭在调用时的原始范围中取值为i

+0

不应被理解为'i'不可循环 – EpicKip

+0

@EpicKip它在外面。请参阅我在答案中链接的博文。 –

+0

请参阅:https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-the-loop-variable-considered-harmful/&https://blogs.msdn.microsoft.com/ ericlippert/2009/11/16/closed-over-the-loop-variable-part-two/ – PaulF

4

这是因为参考‘“委托在for循环并补充说:’到我存储

不,这不是问题。问题是委托和被引用的方式值被提取出来,这就是所谓的闭包,委托从循环中提取,并且只有最后一个值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 
} 
+0

根据https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-the -loop-variable-considered-harmful /对于新版本的C#,这个问题不再存在? –

相关问题