匿名函数创建的“闭包”与其他动态语言创建的“闭包”有些不同(我将使用 Javascript 作为示例)。
function thing() {
var o1 = {n:1}
var o2 = {dummy:"Hello"}
return function() { return o1.n++; }
}
var fn = thing();
alert(fn());
alert(fn());
这个小块 javascript 将显示 1 然后 2。匿名函数可以访问 o1 变量,因为它存在于其作用域链中。然而,匿名函数有一个完全独立的作用域,它可以在其中创建另一个 o1 变量,从而隐藏作用域链下的任何其他变量。还要注意,整个链中的所有变量都保留下来,因此只要 fn 变量持有函数引用,o2 就会继续存在持有对象引用。
现在与 C# 匿名函数进行比较:-
class C1 { public int n {get; set;} }
class C2 { public string dummy { get; set; } }
Func<int> thing() {
var o1 = new C1() {n=1};
var o2 = new C2() {dummy="Hello"};
return delegate { return o1.n++; };
}
...
Func<int> fn = thing();
Console.WriteLine(fn());
Console.WriteLine(fn());
在这种情况下,匿名函数不会创建真正独立的范围,就像任何其他函数内 {} 代码块中的变量声明(用于 a foreach
,if
等)
因此,同样的规则适用,块外的代码不能访问块内声明的变量,但你也不能重用标识符。
当匿名函数被传递到创建它的函数之外时,就会创建一个闭包。与 Javascript 示例的不同之处在于,只有匿名函数实际使用的那些变量才会保留,因此在这种情况下,o2 持有的对象将一旦事情完成就可以用于GC,