匿名方法實現
編譯器為匿名方法生成的代碼很大程度上依賴於匿名方 法使用的參數或變量的類型。例如,匿名方法使用其包含方法的局部變量(也叫 做外部變量)還是使用類成員變量和方法參數?無論是哪一種情況,編譯器都會 生成不同的 MSIL。如果匿名方法不使用外部變量(也就是說,它只使用自己的參 數或者類成員),則編譯器會將一個私有方法添加到該類中,以便賦予方法一個 唯一的名稱。該方法的名稱具有以下格式:
<return type> __AnonymousMethod$<random unique number>(<params>)
和其他編譯器生成的成員一樣,這都是會改變的,並且最有可能在最 終版本發布之前改變。方法簽名將成為它指派的委托的簽名。
編譯器只是 簡單地將匿名方法定義和賦值轉換成推理委托類型的標准實例,以包裝機器生成 的私有方法:
SomeDelegate del = new SomeDelegate (__AnonymousMethod$00000000);
非常有趣的是,機器產生的私有方法 並不顯示在 IntelliSense 中,也不能顯式地調用它,因為其名稱中的美元符號 對於 C# 方法來說是一個非法標記(但它是一個有效的 MSIL 標記)。
當 匿名方法使用外部變量時,情況會更加困難。如果這樣,編譯器將用下面的格式 添加具有唯一名稱的私有嵌套類:
__LocalsDisplayClass$<random unique number>
嵌套類有一個名為 <this> 的指向包含類的引用, 它是一個有效的 MSIL 成員變量名。嵌套類包含與匿名方法使用的每個外部變量 對應的公共成員變量。編譯器向嵌套類定義中添加一個具有唯一名稱的公共方法 ,格式如下:
<return type> __AnonymousMethod$<random unique number>(<params>)
方法簽名將成為被指派的委托的簽名。編譯器用代碼替代匿名方法定 義,此代碼創建一個嵌套類的實例,並進行必要的從外部變量到該實例的成員變 量的賦值。最後,編譯器創建一個新的委托對象,以便包裝嵌套類實例的公共方 法,然後調用該委托來調用此方法。圖 9 用 C# 偽代碼展示了編譯器為圖 7 中 定義的匿名方法生成的代碼。
Figure 9Anonymous Method Code with Outer Variables
class SomeClass
{
string m_Space = " ";
delegate void SomeDelegate(string str);
private sealed class __LocalsDisplayClass$00000001
{
public SomeClass <this>; //Back pointer, name is valid in MSIL
public string msg; //Outer variable
public void __AnonymousMethod$00000000(string name)
{
MessageBox.Show(msg + <this>.m_Space + name);
}
}
public void InvokeMethod()
{
string msg = "Hello";
__LocalsDisplayClass$00000001 locals;
locals = new __LocalsDisplayClass$00000001();
locals.<this> = this;
locals.msg = msg;
SomeDelegate del = new
SomeDelegate(locals.__AnonymousMethod$00000000);
del("Juval");
}
圖 9