使用反射将事件处理程序绑定到任何类型的事件

本文关键字:任何 类型 事件 绑定 程序 反射 事件处理 | 更新日期: 2023-09-27 18:28:38

我有一些代码需要将事件动态绑定到事件处理程序:

foreach (string evnt in attribute.Events)
{
    EventInfo ei = control.GetType().GetEvent(evnt);
    if(ei != null)
    {
        ei.AddEventHandler(control, new EventHandler((s, e) =>
        {
            // More awesomeness here...
        }));
    }
}

因此,对于事件列表中的每个字符串,从控件获取事件并绑定一个处理程序。

问题是并非所有事件都是EventHandler,例如,有些事件可能是KeyEventHanderMouseEventHandler等。

我不想要EventHandler派生类型的大量if/else列表,我只想绑定相同的处理程序,而不管它是什么类型的EventHandler

我该怎么做?

使用反射将事件处理程序绑定到任何类型的事件

这里有一种方法:

首先创建这个助手类:

public class HandlerHelper<T> where T : EventArgs
{
    private readonly EventHandler m_HandlerToCall;
    public HandlerHelper(EventHandler handler_to_call)
    {
        m_HandlerToCall = handler_to_call;
    }
    public void Handle(object sender, T args)
    {
        m_HandlerToCall.Invoke(sender, args);
    }
}

这个泛型类有一个Handle方法,它将被用作许多事件处理程序类型的委托。请注意,这个类是泛型的。T将是用于不同事件类型的许多EventArgs派生类之一。

现在假设您定义以下事件处理程序:

var event_handler = new EventHandler((s, args) =>
{
    // More awesomeness here...
});

以下是如何使用helper类为将调用event_handler:的不同事件处理程序类型创建不同的委托

foreach (var event_name in event_names)
{
    var event_info = control.GetType().GetEvent(event_name);
    var event_handler_type = event_info.EventHandlerType;
    var event_args_type = event_handler_type.GetMethod("Invoke").GetParameters()[1].ParameterType;
    var helper_type = typeof(HandlerHelper<>).MakeGenericType(event_args_type);
    var helper = Activator.CreateInstance(helper_type, event_handler);
    Delegate my_delegate = Delegate.CreateDelegate(event_handler_type, helper, "Handle");
    event_info.AddEventHandler(button, my_delegate);
}

对于每个事件,我们获得类似于EventHandlerMouseEventHandlerEventHandlerType

然后我们使用反射来获得第二个参数的类型,它类似于EventArgsMouseEventArgs

然后,我们根据EventArgs参数的类型创建一个HandlerHelper<>的实例。例如CCD_ 17或CCD_。

我们将event_handler赋予HandlerHelper的构造函数,以便它可以在调用其Handle方法时调用它。

这使得Handle方法的签名成为我们想要的。例如,在HandlerHelper<MouseEventArgs>的情况下,Handle方法的签名是:

void Handle(object sender, MouseEventArgs args)

现在,我们使用Delegate.CreateDelegate为我们创建的特定HandlerHelper对象创建一个基于Handle方法的委托,并将此委托赋予AddEventHandler方法。

出于性能原因,可以基于event_args_type缓存委托(而不是每次创建一个)。

您可以使用动态关键字来附加处理程序。您可以在此处找到更多解释:https://msdn.microsoft.com/en-us/library/ms228976(v=vs.110).aspx