为运行时加载的DLL中的WinForm附加事件处理程序
解决反射加载WinForm DLL时绑定自定义事件的问题
问题原因
反射创建的窗体实例编译时类型为Object,编译器无法识别该类型上定义的ImDone自定义事件,直接通过实例访问事件会触发编译报错。
解决方案
以下两种方式可实现事件绑定并获取返回参数:
方法1:纯反射实现事件绑定与参数解析
完全依赖反射机制,无需提前引用目标DLL,适合无法预知事件参数类型的场景:
- 定义事件处理方法,用
object接收事件参数:
private void HandleImDone(object sender, object e) { // 通过反射获取事件参数中的RetVal属性 var retValProp = e.GetType().GetProperty("RetVal"); if (retValProp != null) { var returnValue = retValProp.GetValue(e); // 在这里处理返回参数 Console.WriteLine($"获取到返回值:{returnValue}"); } }
- 反射加载DLL、创建实例并绑定事件:
// 加载网络路径下的目标DLL var targetAssembly = Assembly.LoadFrom(@"\\network-path\WinFormApp.dll"); // 获取FrmMain的类型信息 var frmMainType = targetAssembly.GetType("WinFormApp.FrmMain"); // 创建窗体实例 var formInstance = Activator.CreateInstance(frmMainType); // 获取ImDone事件的EventInfo对象 var imDoneEvent = frmMainType.GetEvent("ImDone"); if (imDoneEvent != null) { // 创建与事件委托签名匹配的委托实例 var handlerDelegate = Delegate.CreateDelegate( imDoneEvent.EventHandlerType, this, typeof(YourMainClass).GetMethod("HandleImDone", BindingFlags.NonPublic | BindingFlags.Instance) ); // 绑定事件处理程序 imDoneEvent.AddHandler(formInstance, handlerDelegate); } // 调用Show方法显示窗体 frmMainType.GetMethod("Show").Invoke(formInstance, null);
方法2:使用dynamic简化操作
若可接受运行时类型检查,dynamic能大幅简化代码编写:
- 定义事件处理方法,用
dynamic接收事件参数:
private void HandleImDone(object sender, dynamic e) { // 直接访问RetVal属性,由dynamic在运行时解析类型 var returnValue = e.RetVal; // 处理返回参数 Console.WriteLine($"获取到返回值:{returnValue}"); }
- 加载DLL并绑定事件:
var targetAssembly = Assembly.LoadFrom(@"\\network-path\WinFormApp.dll"); var frmMainType = targetAssembly.GetType("WinFormApp.FrmMain"); // 用dynamic声明实例,绕过编译时类型检查 dynamic formInstance = Activator.CreateInstance(frmMainType); // 直接绑定事件 formInstance.ImDone += HandleImDone; // 显示窗体 formInstance.Show();
关键注意事项
- 事件处理方法的签名必须与目标DLL中
ImDone事件的委托签名完全一致(参数数量、类型、返回值需严格匹配)。 - 若目标DLL使用自定义委托类型,反射方式中需确保
Delegate.CreateDelegate使用imDoneEvent.EventHandlerType指定的委托类型。
内容的提问来源于stack exchange,提问作者Sphinx
相关产品推荐
相关产品推荐

