C# 使用反射动态订阅泛型EventHandler事件时报指定转换无效错误求助
问题根因
出现Specified cast is not valid异常有两个核心原因:
- 委托类型不匹配:你定义的事件是泛型委托
EventHandler<PowerStateEventsArgs>,但绑定事件时你用的是非泛型的EventHandler,两者类型不兼容,所以抛出转换失败异常。 AddEventHandler参数传值错误:你的事件是静态事件,该方法第一个参数对于静态事件应传入null,对于实例事件才需要传入类的实例对象,你之前传入d._projectors.fullClass(Type类型对象)属于参数错误。
可行解决方案
方案1:已知事件参数类型直接绑定
适合事件数量少、参数类型已知的场景,代码如下:
foreach(var evnt in d._projectors._events) { EventInfo ev = evnt.Value; try { if (evnt.Key == "OnPowerStateRecieved") { // 静态事件第一个参数传null,委托使用对应泛型类型 ev.AddEventHandler(null, new EventHandler<PowerStateEventsArgs>(DisplayChangeEvents.DisplayPowerChangedEvent)); } else if (evnt.Key == "OnMuteStateRecieved") { // 按实际的静音事件参数类型替换MuteStateEventsArgs ev.AddEventHandler(null, new EventHandler<MuteStateEventsArgs>(DisplayChangeEvents.DisplayMuteChangedEvent)); } } catch (Exception ex) { ErrorLog.Error("Error creating event handlers : " + ex.Message + "\r"); } }
注意对应处理方法的签名必须和委托匹配,比如DisplayPowerChangedEvent的签名应为:
public static void DisplayPowerChangedEvent(object sender, PowerStateEventsArgs e) { // 你的处理逻辑 }
方案2:动态创建委托实现通用绑定
适合事件数量多、需要统一处理绑定逻辑的场景,不需要手动指定泛型参数:
foreach(var evnt in d._projectors._events) { EventInfo ev = evnt.Value; try { Type delegateType = ev.EventHandlerType; MethodInfo handleMethod = null; // 匹配事件对应的处理方法 switch(evnt.Key) { case "OnPowerStateRecieved": handleMethod = typeof(DisplayChangeEvents).GetMethod(nameof(DisplayChangeEvents.DisplayPowerChangedEvent)); break; case "OnMuteStateRecieved": handleMethod = typeof(DisplayChangeEvents).GetMethod(nameof(DisplayChangeEvents.DisplayMuteChangedEvent)); break; } if(handleMethod != null) { Delegate handler = Delegate.CreateDelegate(delegateType, handleMethod); // 静态事件传null,实例事件替换为你实际使用的类实例对象 ev.AddEventHandler(null, handler); } } catch (Exception ex) { ErrorLog.Error("Error creating event handlers : " + ex.Message + "\r"); } }
额外注意事项
- 如果你后续改为使用实例事件而非静态事件,
AddEventHandler第一个参数必须传入你程序中实际用来调用类方法的那个实例,不能每次临时Activator.CreateInstance创建新实例,否则新实例的事件触发和你正在使用的实例无关,无法收到事件通知。 - 如果你自己修改了事件的访问器逻辑,要确保自定义的add访问器没有做额外的类型校验,避免合法委托被拦截。
内容的提问来源于stack exchange,提问作者cmac_t0ld
相关产品推荐
相关产品推荐

