但對於有多個局部變量作用域的情況就比較復雜了,例如GrantRi在其例子中給出的代碼
以下為引用:
delegate void NoArgs();
void SomeMethod()
{
NoArgs [] methods = new NoArgs[10];
int outer = 0;
for (int i = 0; i < 10; i++)
{
int inner = i;
methods[i] = delegate {
Console.WriteLine("outer = {0}", outer++);
Console.WriteLine("i = {0}", i);
Console.WriteLine("inner = {0}", ++inner);
};
methods[i]();
}
for (int j = 0; j < methods.Length; j++)
methods[j]();
}
就需要一個類封裝變量outer;一個類封裝變量i;另外一個類封裝inner和匿名函數,並引用前面兩個封裝類的實例。因為變量outer、i和inner有著不同的作用域,呵呵。偽代碼如下:
以下為引用:
private sealed class __LocalsDisplayClass$00000008
{
public int outer;
};
private sealed class __LocalsDisplayClass$0000000a
{
public int i;
};
private sealed class __LocalsDisplayClass$0000000c
{
public int inner;
public __LocalsDisplayClass$00000008 $locals$00000009;
public __LocalsDisplayClass$0000000a $locals$0000000b;
public void __AnonymousMethod$00000007()
{
Console.WriteLine("outer = {0}", this.$locals$00000009.outer++);
Console.WriteLine("i = {0}", this.$locals$0000000b.i);
Console.WriteLine("inner = {0}", ++this.inner);
}
};
public void SomeMethod()
{
NoArgs [] methods = new NoArgs[10];
__LocalsDisplayClass$00000008 local1 = new __LocalsDisplayClass$00000008();
local1.outer = 0;
__LocalsDisplayClass$0000000a local2 = new __LocalsDisplayClass$0000000a();
local2.i = 0;
while(local2.i < 10)
{
__LocalsDisplayClass$0000000c local3 = new __LocalsDisplayClass$0000000c();
local3.$locals$00000009 = local1;
local3.$locals$0000000b = local2;
local3.inner = local1.i;
methods[local2.i] = new NoArgs(local3.__AnonymousMethod$00000007);
methods[local2.i]();
}
for (int j = 0; j < methods.Length; j++)
methods[j]();
}
總結其規律就是每個不同的局部變量作用域會有一個單獨的類進行封裝,子作用域中如果使用到父作用域的局部變量,則子作用域的封裝類引用父作用域的封裝類。相同作用域的變量和匿名方法由封裝類綁定到一起,維護其一致的生命周期。
相對於MS較為復雜的實現,Delphi.Net對嵌套函數則使用較為簡單的參數傳遞方式,因為嵌套函數沒有那麼復雜的變量生命期管理要求,如
以下為引用:
procedure SayHello;
var
Name: string;
procedure Say;
begin
WriteLn(Name);
end;
begin
Name := 'FlIEr Lu';
Say;
end;
系統生成函數Say代碼時,將使用到的上級變量如Name放入到一個自動生成的類型($Unnamed1)中,然後作為函數參數傳遞給Say函數,偽代碼類似
以下為引用:
type
$Unnamed1 = record
Name: string;
end;
procedure @1$SayHello$Say(var UnnamedParam: $Unnamed1);
begin
WriteLn(UnnamedParam.Name);
end;
procedure SayHello;
var
Name: string;
Unnamed1: $Unnamed1;
begin
Name := 'FlIEr Lu';
Unnamed1.Name := Name;
Say(Unnamed1);
end;