.NET反射绑定含自定义参数的事件委托问题求助
解决.NET 4.5.2中反射绑定带自定义事件参数的委托问题
这个问题的核心在于委托签名必须严格匹配——虽然你的处理方法参数用EventArgs是兼容的(因为OldClassEventArgs继承自它),但CLR默认不会自动允许这种跨类型的委托绑定,必须通过特定的反射API来处理。下面是两种可行的解决方案,亲测在.NET 4.5.2环境下有效:
方法一:利用Delegate.CreateDelegate的兼容绑定重载
这是最简单的方案,Delegate.CreateDelegate有一个重载允许我们开启"签名兼容"模式,只要参数类型是协变的(比如子类转父类),就能成功绑定。
步骤代码:
- 先获取所有需要的类型信息:
// 加载目标网站的程序集(替换成实际的程序集名称,比如"WebsiteAssembly") Assembly targetAssembly = Assembly.Load("WebsiteAssembly"); // 获取OldClass类型 Type oldClassType = targetAssembly.GetType("YourNamespace.OldClass"); // 获取嵌套的OldClassEventArgs类型 Type oldClassEventArgsType = oldClassType.GetNestedType("OldClassEventArgs"); // 获取事件对应的委托类型 EventInfo oldClassEventInfo = oldClassType.GetEvent("OldClassEvent"); Type eventDelegateType = oldClassEventInfo.EventHandlerType;
- 定义你的事件处理方法(参数用
EventArgs即可):
private void MyCustomEventHandler(object sender, EventArgs e) { // 这里可以通过反射访问OldClassEventArgs的属性/方法 // 示例:获取名为"EventData"的属性值 PropertyInfo eventDataProp = e.GetType().GetProperty("EventData"); if (eventDataProp != null) { object eventData = eventDataProp.GetValue(e); // 处理你的业务逻辑 Console.WriteLine($"捕获到事件,数据:{eventData}"); } }
- 创建兼容的委托并绑定事件:
// 获取你自己的处理方法的MethodInfo MethodInfo handlerMethod = typeof(YourCurrentClass).GetMethod( "MyCustomEventHandler", BindingFlags.NonPublic | BindingFlags.Instance ); // 关键:使用CreateDelegate的重载,最后一个参数设为true开启兼容绑定 Delegate eventHandler = Delegate.CreateDelegate( eventDelegateType, this, // 你的处理方法所属的实例 handlerMethod, true // 允许绑定到签名兼容的方法(协变参数) ); // 创建OldClass实例(如果已有实例可以直接用) object oldClassInstance = Activator.CreateInstance(oldClassType); // 绑定事件 oldClassEventInfo.AddEventHandler(oldClassInstance, eventHandler);
方法二:用动态方法创建签名匹配的包装器
如果方法一因为某些环境限制(比如权限或程序集加载问题)无法工作,可以用DynamicMethod生成一个签名完全匹配OldClassEventDelegate的包装方法,在包装方法内部调用你的处理逻辑。
步骤代码:
在获取好所有类型信息和处理方法后,添加以下代码:
// 创建动态方法,签名和OldClassEventDelegate完全一致 DynamicMethod eventWrapper = new DynamicMethod( "OldClassEventWrapper", typeof(void), new Type[] { typeof(object), oldClassEventArgsType }, // 委托的参数类型:sender + OldClassEventArgs typeof(YourCurrentClass).Module ); // 生成IL代码,把OldClassEventArgs转成EventArgs后调用你的处理方法 ILGenerator il = eventWrapper.GetILGenerator(); // 加载第一个参数(sender) il.Emit(OpCodes.Ldarg_0); // 加载第二个参数(OldClassEventArgs实例),并转换为EventArgs il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Castclass, typeof(EventArgs)); // 调用你的处理方法 il.Emit(OpCodes.Call, handlerMethod); // 方法返回 il.Emit(OpCodes.Ret); // 从动态方法创建委托 Delegate eventHandler = eventWrapper.CreateDelegate(eventDelegateType, this); // 绑定事件(和方法一相同) oldClassEventInfo.AddEventHandler(oldClassInstance, eventHandler);
额外:调用OldClassMethod方法
完成事件绑定后,调用目标方法直接用反射即可:
MethodInfo oldClassMethod = oldClassType.GetMethod( "OldClassMethod", BindingFlags.Public | BindingFlags.Instance ); // 如果方法有参数,替换null为参数数组即可 oldClassMethod.Invoke(oldClassInstance, null);
注意事项
- 确保你能正确加载网站的程序集:如果网站程序集在bin目录下,也可以用
Assembly.LoadFrom指定路径加载,但要注意文件锁定问题。 - 权限:生产环境下反射需要足够的权限,确保你的DLL部署后有对应的执行权限。
- 事件清理:如果需要解绑事件,记得保存好创建的
eventHandler实例,后续调用eventInfo.RemoveEventHandler即可。
内容的提问来源于stack exchange,提问作者freefaller
相关产品推荐
相关产品推荐

