關於委派與事件的介紹網路上汗牛充棟,本文不重複基礎概念,而是從「反射」角度切入,直接觀察委派型別在運行時的成員結構,驗證「委派是一個類別、事件是委派型別的實例」這一本質認知。
delegate void DelegateDemo();
static event DelegateDemo delHandle;
static void Main() {
delHandle += new DelegateDemo(MyDelegate_delHandle);
// 取得事件的運行時型別(實際上是委派型別)
MemberInfo[] mis = delHandle.GetType().GetMembers();
foreach (var item in mis) {
Console.WriteLine($"{item.Name} {item}");
}
}
static void MyDelegate_delHandle() {
throw new NotImplementedException();
}
輸出包含以下關鍵成員(節錄):
Invoke - 同步呼叫委派方法BeginInvoke / EndInvoke - 非同步呼叫模式GetInvocationList - 取得調用清單(多播委派核心)Method、Target - 封裝的方法資訊與目標物件System.MulticastDelegate → System.Delegate → System.Object
偵錯視窗清晰顯示:委派型別擁有完整的類別成員結構,委派確實是一個衍生自 MulticastDelegate 的密封類別。
程式碼中 delHandle.GetType() 取得的是事件欄位的運行時型別(即委派型別)。若改為 typeof(DelegateDemo) 結果相同。這證明:
事件就是類別中的一個委派型別實例(欄位),受add/remove存取器封裝,僅允許+=/-=操作,防止外部直接呼叫Invoke或覆寫調用清單。
Func<Base> ← Func<Derived>)Action<Derived> ← Action<Base>)反射揭示了委派的類別本質與事件的封裝機制。更底層的 IL 分析(如 .ctor、Invoke 簽章)可進一步印證,但對日常開發而言,理解「委派=類別、事件=受保護的委派實例」已足夠指導正確使用模式。