《框架設計(第二版)》:CLR Via C# —— 15.4 委托揭秘(P281)
public class DelegateTest {
protected delegate void MyDelegate();
private void TestMethod() { }
private void Method() {
MyDelegate aMyDelegate = new MyDelegate(TestMethod);
Method(aMyDelegate);
}
private void Method(MyDelegate aMyDelegate) {
if (aMyDelegate != null) aMyDelegate();
}
}
編譯器將 public delegate void MyDelegate(); 轉換為完整類別:
public class MyDelegate : System.MulticastDelegate {
public MyDelegate(Object @object, IntPtr method); // 建構子
public virtual void Invoke(); // 同步呼叫
public virtual IAsyncResult BeginInvoke(AsyncCallback callback, object @object); // 非同步開始
public virtual void EndInvoke(IAsyncResult result); // 非同步結束
}
可用 ILDasm.exe 驗證生成的元數據。所有委托類型繼承 MulticastDelegate,後者繼承 Delegate,再繼承 Object。FCL 歷史原因導致雙基類,需同時了解兩者。
| 欄位 | 型別 | 說明 |
|---|---|---|
_target | System.Object | 靜態方法為 null;實例方法指向調用對象(隱式 this 參數) |
_methodPtr | System.IntPtr | CLR 內部整數,標識回調方法 |
_invocationList | System.Object | 通常為 null;多播委托時引用委托陣列 |
原始碼傳遞 TestMethod,編譯器解析為物件引用與方法標識 IntPtr,分別存入 _target、_methodPtr,並將 _invocationList 設為 null。每個委托物件實際封裝一個方法及其調用對象。
代碼 aMyDelegate(); 編譯器轉為 aMyDelegate.Invoke();。Invoke 簽名與委托一致,內部使用 _target、_methodPtr 對指定物件呼叫方法。ILDasm 可驗證生成的 IL 代碼確實呼叫 Invoke。
委托表面簡單,實則編譯器與 CLR 做大量幕後工作隱藏複雜性。理解其內部結構有助於更好地使用委托。