C# 如何使用反射将事件处理程序附加到事件?

C# 如何使用反射将事件处理程序附加到事件?,c#,events,reflection,event-handling,delegates,C#,Events,Reflection,Event Handling,Delegates,我知道EventInfo.AddEventHandler(…)方法,该方法可用于将处理程序附加到事件。但是,如果我甚至不能定义事件处理程序的正确签名,比如,我甚至没有对处理程序期望的事件参数的引用,该怎么办 我将用正确的代码解释这个问题 //场景当我的解决方案中有所有可用内容时,零反射场景 internal class SendCommentsManager { public void Customize(IRFQWindowManager rfqWindowManager) {

我知道
EventInfo.AddEventHandler(…)
方法,该方法可用于将处理程序附加到事件。但是,如果我甚至不能定义事件处理程序的正确签名,比如,我甚至没有对处理程序期望的事件参数的引用,该怎么办

我将用正确的代码解释这个问题

//场景当我的解决方案中有所有可用内容时,零反射场景

internal class SendCommentsManager
{
    public void Customize(IRFQWindowManager rfqWindowManager)
    {
        rfqWindowManager.SendComment += HandleRfqSendComment;
    }

    private void HandleRfqSendComment(object sender, SendCommentEventArgs args)
    {
        args.Cancel = true;
    }
}
现在,我想通过使用反射来实现同样的目标。我已经能够理解其中的大部分,但是当我将委托附加到事件时(使用
AddEventHandler
),它抛出
“错误绑定到目标方法”。
异常

我理解此异常背后的原因,将错误的委托附加到事件。但一定有办法做到这一点

 internal class SendCommentsManagerUsingReflection
 {
     public void Customize(IRFQWindowManager rfqWindowManager)
     {
         EventInfo eventInfo = rfqWindowManager.GetType().GetEvent("SendComment");
         eventInfo.AddEventHandler(rfqWindowManager, 
             Delegate.CreateDelegate(eventInfo.EventHandlerType, this, "HandleRfqSendComment"));
         //<<<<<<<<<<ABOVE LINE IS WHERE I AM GOING WRONG>>>>>>>>>>>>>>
     }

     private void HandleRfqSendComment(object sender, object args)
     {
         Type sendCommentArgsType = args.GetType();
         PropertyInfo cancelProperty = sendCommentArgsType.GetProperty("Cancel");
         cancelProperty.SetValue(args, true, null);
     }
 }
内部类SendCommentsManagerUsingReflection
{
公共无效自定义(IRFQWindowManager rfqWindowManager)
{
EventInfo EventInfo=rfqWindowManager.GetType().GetEvent(“SendComment”);
eventInfo.AddEventHandler(rfqWindowManager,
CreateDelegate(eventInfo.EventHandlerType,此为“HandleRfqSendComment”);
//>>>>
}
私有void HandleRfqSendComment(对象发送者、对象参数)
{
键入sendCommentArgsType=args.GetType();
PropertyInfo cancelProperty=sendCommentArgsType.GetProperty(“取消”);
cancelProperty.SetValue(args,true,null);
}
}

我认为您的代码失败了,因为
HandleRfqSendComment
是私有的。相反,您可以直接创建该方法的委托,而无需将其名称传递给
CreateDelegate
。然后需要使用以下方法将委托转换为所需类型:

public static Delegate ConvertDelegate(Delegate originalDelegate, Type targetDelegateType)
{
    return Delegate.CreateDelegate(
        targetDelegateType,
        originalDelegate.Target,
        originalDelegate.Method);
}
在代码中,可以按如下方式使用此方法:

EventInfo eventInfo = rfqWindowManager.GetType().GetEvent("SendComment");
Action<object, object> handler = HandleRfqSendComment;
Delegate convertedHandler = ConvertDelegate(handler, eventInfo.EventHandlerType);
eventInfo.AddEventHandler(rfqWindowManager, convertedHandler);
EventInfo EventInfo=rfqWindowManager.GetType().GetEvent(“SendComment”);
操作处理程序=HandleRfqSendComment;
Delegate convertedHandler=ConvertDelegate(handler,eventInfo.EventHandlerType);
eventInfo.AddEventHandler(rfqWindowManager、convertedHandler);

这是对已经非常棒的答案的一个小小补充。这里有一个助手类,您可以使用它来订阅带有操作的事件

公共静态部分类ReactiveExtensions
{
公共静态事件处理程序CreateGenericHandler(对象目标,MethodInfo方法)
{
返回(EventHandler)委托
.CreateDelegate(类型为(EventHandler),
目标、方法);
}
公共静态EventHandler CreateHandler(对象目标,MethodInfo方法)
{
返回(EventHandler)委托
.CreateDelegate(类型为(EventHandler),
目标、方法);
}
静态void BindEventToAction(对象目标、事件信息、委托操作)
{
方法信息法;
if(eventInfo.EventHandlerType.IsGenericType)
{
方法=类型(反应扩展)
.GetMethod(名称(CreateGenericHandler))
.MakeGenericMethod(
eventInfo.EventHandlerType.GetGenericArguments());
}
其他的
{
方法=类型(反应扩展)
.GetMethod(nameof(CreateHandler));
}
Delegate@Delegate=(Delegate)方法。Invoke(null,
新对象[]{action.Target,action.Method});
eventInfo.AddEventHandler(目标,@delegate);
}
}
以下是如何使用此功能的示例:

公共静态部分类ReactiveExtensions
{
公共静态void Subscribe(T源,字符串eventName)
{
EventInfo EventInfo=typeof(T).GetEvent(eventName);
行动行动=(s,e)=>
{
Console.WriteLine(“调用的事件”);
};
BindEventToAction(源、事件信息、操作);
}
}

为什么不使用SendCommentEventArgs作为第二个参数?顺便说一句:看一看:我不想引用具有“SendCommentEventArgs”的最新版本的dll。如果我可以使用“SendCommentEventArgs”,那么就没有必要使用反射附加事件处理程序。