下面的代码段将输出数字“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.“
我的问题是:为什么是“存储”的“参考”?
答案 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
值取为当前值。