如何在运行时向事件添加更通用的事件处理程序

本文关键字:事件处理 程序 添加 运行时 事件 | 更新日期: 2023-09-27 18:31:37

如果我有一个继承自 EventArgs 的类型(我们称之为 EventArgs1),以及从 EventArgs1 继承的另外一堆

类(让我们将它们统称为 EventArgsX),然后是一堆类型为 EventHandler<EventArgsX> 的事件,如果在运行时我被传递给这些事件之一的 EventInfo,并且我想添加一个需要 EventArgs1 类型的第二个参数的事件处理程序(例如 MyEventHandler(object sender, EventArgs1 e) ) 我该怎么做?

如果事件是 EventHandler<EventArgs1> 类型,那么我将这样做:

eventInfo.AddEventHandler(this, new EventHandler<EventArgs1>(MyEventHandler));

但是当事件类型为 EventHandler<EventArgsX> 时,这会引发异常,并且由于我不知道编译时的 EventArgsX 是什么,因此我不能简单地新建一个EventHandler<EventArgsX> 如果我确实知道我在编译时将处理程序添加到哪个事件,那么这将是完全可以接受的:

MyEvent += MyEventHandler

但我根本无法弄清楚如何在运行时执行此操作。有什么建议吗?

如何在运行时向事件添加更通用的事件处理程序

我不能简单地重新建立EventHandler<EventArgsX>

当然可以,尽管您需要使用Delegate.CreateDelegate()和反射来做到这一点。假设MyEventHandlerthis上的实例方法,您可以这样做:

var eventInfo = …;
EventHandler<EventArgs1> badHandler = MyEventHandler;
var goodHandler = Delegate.CreateDelegate(
    eventInfo.EventHandlerType, this, badHandler.Method);
eventInfo.AddEventHandler(this, goodHandler);

更新

基本上,我已经倒着读了这个问题;我将留下这个答案,以防其他试图做相反事情的人发现这个问题。


基本上,你不能做你想做的事情。 如果委托的 EventArgs 类型是事件声明类型的子类,则事件无法添加委托。 您尝试在输入参数逆变时使用协方差。

假设这些类

class EventArgs1 : EventArgs {}
class EventArgsA : EventArgs1 {}
class EventArgsB : EventArgs1 {}

考虑一下如果可以将方法void Handle(object sender, EventArgsA args)添加到具有签名void SomeEvent(object sender, EventArgs1 args)的事件中会发生什么情况。 事件源可能会执行以下操作:

if (SomeEvent != null)
{
    var args = new EventArgsB();
    SomeEvent(this, args);      //this line is perfectly legal, as EventArgsB inherits from EventArgs1.
}

但是,当运行时到达事件调用列表中的此委托时,它现在必须将args对象传递给Handle(object, EventArgsA),这当然不能,因为 EventArgsB 实例不是 EventArgsA 实例。 将导致运行时异常。 实际上,当您添加委托时会捕获不匹配,因此会引发异常。