涉及到闭包(closure)的概念。
不同语言对闭包选择了不同的支持,相比之下,C#中就能够在匿名函数中引用非final的外部变量,例如这篇帖子中提到的C#代码:
List<Func<int>> actions = new List<Func<int>>();
int variable = 0;
while (variable < 5)
{
actions.Add(() => variable * 2);
++ variable;
}
foreach (var act in actions)
{
Console.WriteLine(act.Invoke());
}
这一行:
actions.Add(() => variable * 2);
就在匿名方法内引用了外部局部变量: variable.
但同时也引起了一个奇怪的问题,上面的C#代码,我们期望的结果应该是输出"0, 2, 4, 6, 8"才对,结果却是10个零。
原因就是C# compiler 在所闭的包内圈入了对variable的引用,然后当运行
Console.WriteLine(act.Invoke());
时,variable值已经变成5,结果输出为10个零。
这种特性多少有点令人意外,可能java正是为了避免这种情形,于是强制规定闭包内引用的外部局部变量必须为final,想象一下如果上例中variable 为final的话,自然就不会写出上面的代码,造成类似的意外了。
另外,上例中如果你希望达到输出"0, 2, 4, 6, 8"的效果,可以:
while (variable < 5)
{
int copy = variable;
actions.Add(() => copy * 2);
++ variable;
}
ps.参考了很多文章,理解也仍然算不上透彻,列举在下,供包括自己的后来人参考
http://stackoverflow.com/questions/271440/c-captured-variable-in-loop
http://blogs.msdn.com/b/ericlippert/archive/2003/09/17/what-are-closures.aspx
http://csharpindepth.com/Articles/Chapter5/Closures.aspx
http://en.wikipedia.org/wiki/Closure_(computer_science)
http://zh.wikipedia.org/wiki/%E9%97%AD%E5%8C%85_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)