【问题标题】:How to attach event handler to an event using reflection?如何使用反射将事件处理程序附加到事件?
【发布时间】:2010-06-25 18:22:09
【问题描述】:

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

我会用正确的代码解释问题。

// 解决方案中所有可用的场景,零反射场景。

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

    private void HandleRfqSendComment(object sender, SendCommentEventArgs args)
    {
        args.Cancel = true;
    }
}

现在,我想通过使用反射来实现相同的目标。我已经能够弄清楚其中的大部分,但是当我将代表附加到事件时(使用AddEventHandler),它会抛出"Error binding to target method." 异常。

我了解此异常背后的原因,将错误的委托附加到事件。但必须有某种方法来实现这一点。

 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);
     }
 }

【问题讨论】:

  • 为什么不使用 SendCommentEventArgs 作为第二个参数?顺便说一句:看看:msdn.microsoft.com/library/…
  • 我不想引用具有“SendCommentEventArgs”的最新版本的 dll。如果我可以使用“SendCommentEventArgs”,则无需使用反射附加事件处理程序。

标签: c# events reflection event-handling delegates


【解决方案1】:

我认为您的代码失败了,因为 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);

【讨论】:

    【解决方案2】:

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

    public static partial class ReactiveExtensions
    {
        public static EventHandler<TEvent> CreateGenericHandler<TEvent>(object target, MethodInfo method)
        {
            return (EventHandler<TEvent>)Delegate
                .CreateDelegate(typeof(EventHandler<TEvent>), 
                target, method);
        }
    
        public static EventHandler CreateHandler(object target, MethodInfo method)
        {
            return (EventHandler)Delegate
                .CreateDelegate(typeof(EventHandler),
                target, method);
        }
            
            
        static void BindEventToAction(object target, EventInfo eventInfo, Delegate action)
        {
            MethodInfo method;
    
            if (eventInfo.EventHandlerType.IsGenericType)
            {
                method = typeof(ReactiveExtensions)
                    .GetMethod(nameof(CreateGenericHandler))
                    .MakeGenericMethod(
                    eventInfo.EventHandlerType.GetGenericArguments());
            }
            else
            {
                method = typeof(ReactiveExtensions)
                    .GetMethod(nameof(CreateHandler));
            }
    
    
            Delegate @delegate = (Delegate)method.Invoke(null,
                new object[] { action.Target, action.Method });
    
    
            eventInfo.AddEventHandler(target, @delegate);
        }
    }
    

    这是一个关于如何使用它的示例:

    public static partial class ReactiveExtensions
    {
        public static void Subscribe<T>(T source, string eventName)
        {
            EventInfo eventInfo = typeof(T).GetEvent(eventName);
    
            Action<object, object> action = (s, e) =>
            {
                Console.WriteLine("Event Called");
            };
    
            BindEventToAction(source, eventInfo, action);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-04-24
      • 1970-01-01
      • 2016-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多