You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET反射绑定含自定义参数的事件委托问题求助

解决.NET 4.5.2中反射绑定带自定义事件参数的委托问题

这个问题的核心在于委托签名必须严格匹配——虽然你的处理方法参数用EventArgs是兼容的(因为OldClassEventArgs继承自它),但CLR默认不会自动允许这种跨类型的委托绑定,必须通过特定的反射API来处理。下面是两种可行的解决方案,亲测在.NET 4.5.2环境下有效:

方法一:利用Delegate.CreateDelegate的兼容绑定重载

这是最简单的方案,Delegate.CreateDelegate有一个重载允许我们开启"签名兼容"模式,只要参数类型是协变的(比如子类转父类),就能成功绑定。

步骤代码:

  1. 先获取所有需要的类型信息:
// 加载目标网站的程序集(替换成实际的程序集名称,比如"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;
  1. 定义你的事件处理方法(参数用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}");
    }
}
  1. 创建兼容的委托并绑定事件:
// 获取你自己的处理方法的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:16:15