为什么“引用”一个int(而不是值)存储?
下面将输出的代码片段数“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 “。
我的问题是:为什么是“参考”我存储?
这不是按值与按参考值的效果。
的输出是10,因为当代表代码运行,这是在第二循环中,并且通过时间会假设的10值可变i
的值被评估,因为这是它与时结束第一个循环退出。
使用调试器在第二个循环中逐步调用printer()
,您会发现委托关闭在调用时的原始范围中取值为i
。
这是因为参考‘“委托在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
}
根据https://blogs.msdn.microsoft.com/ericlippert/2009/11/12/closing-over-the -loop-variable-considered-harmful /对于新版本的C#,这个问题不再存在? –
不应被理解为'i'不可循环 – EpicKip
@EpicKip它在外面。请参阅我在答案中链接的博文。 –
请参阅: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