場景:組件 A 定義事件,組件 B **未引用 A** 卻需在運行時動態訂閱該事件。傳統強型別訂閱失效,需動態反射 + DynamicMethod 發 IL 實現「橋接委託」。
FarEventArgs)(object sender, FarEventArgs e),B 僅持有 EventHandler (sender, EventArgs)
private void btnAttachEvent_Click(object sender, EventArgs e) {
// 1. 取得事件資訊
Type formType = fireEventForm.GetType();
EventInfo evtInfo = formType.GetEvent("SomeEvent");
// 2. 準備目標處理器(簽名:object, EventArgs)
EventHandler tempHandler = new EventHandler(this.farEventHandler);
MethodInfo targetMethod = tempHandler.Method;
// 3. 發射 DynamicMethod:橋接簽名差異
// 目標簽名:void (object, FarEventArgs)
var dm = new DynamicMethod(
"BridgeMethodForAttachEvent",
typeof(void),
new Type[] { typeof(object), assembly.GetType("FireFarEvent.FarEventArgs") },
this.GetType()); // 關聯模組以訪問私有成員
var il = dm.GetILGenerator();
// IL 邏輯:this.farEventHandler(sender, (EventArgs)e)
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0); // this
il.Emit(OpCodes.Ldarg_2); // FarEventArgs e
il.Emit(OpCodes.Ldarg_1); // object sender
il.Emit(OpCodes.Call, targetMethod);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ret);
dm.DefineParameter(1, ParameterAttributes.In, "sender");
dm.DefineParameter(2, ParameterAttributes.In, "e");
// 4. 創建符合事件簽名的委託並掛載
Delegate bridgeDelegate = dm.CreateDelegate(evtInfo.EventHandlerType);
evtInfo.AddEventHandler(fireEventForm, bridgeDelegate);
}
(sender, e),但處理器習慣 (this, e, sender),IL 中 Ldarg_2, Ldarg_1 完成順序交換。FarEventArgs 繼承 EventArgs,傳遞時隱含向上轉型,CLR 自動驗證。DynamicMethod 權限: 建構時傳入 this.GetType() 作為 m 參數,賦予動態方法訪問當前類型私有/內部成員的權限。CreateDelegate(evtInfo.EventHandlerType) 確保生成委託與事件精確匹配。
private void btnDetachEvent_Click(object sender, EventArgs e) {
if (assembly == null || fireEventForm == null || farEventEventInfo == null) return;
farEventEventInfo.RemoveEventHandler(fireEventForm, farEventDelegate);
}
保留 farEventDelegate 引用以便精確移除。
DynamicMethod 結果ReflectionPermission 與 SecurityPermission (UnmanagedCode/ControlEvidence)透過 DynamicMethod 發射橋接 IL,打破編譯期型別依賴,實現真正的「跨組件、無引用、動態事件訂閱」。這是插件系統、擴展點架構的核心基礎設施技術。