【问题标题】:Reflection - Add a Delegate to another Delegate's invocation list反射 - 将委托添加到另一个委托的调用列表
【发布时间】:2015-05-18 11:16:00
【问题描述】:

我正在尝试将委托附加到不同委托的调用列表。 通过这一点,我正在实现一种对现有事件的钩子。 我需要连接在每个被调用的事件之后运行的东西。

只要类型公开的委托和我传入的操作具有完全相同的签名,以下示例有效。 (On1 和 OnAll 事件均使用 Action 委托声明,因此可以正常工作)。

代码:我如何将 Action 与事件修饰符公开的现有委托挂钩。

public static class ReflectionExtensions
{
    public static IEnumerable<EventInfo> GetEvents(this object obj)
    {
        var events = obj.GetType().GetEvents();
        return events;
    }

    public static void AddHandler(this object obj, Action action)
    {
        var events = obj.GetEvents();
        foreach (var @event in events)
        {                    
             @event.AddEventHandler(obj, action);
        }
    }
}

样本:

public class Tester 
{
    public event Action On1;
    public event Action On2;

    public void RaiseOn1()
    {
        On1();
    }

    public void RaiseOn2()
    {
        On2();
    }
}   

class Program
{
    static void Main(string[] args)
    {
        var t = new Tester();
        t.On1 += On1;
        t.On2 += On2;

        t.AddHandler(OnAll);

        t.RaiseOn1();
        t.RaiseOn2();
    }

    public void On1() { }
    public void On2() { }
    public void OnAll() { }
} 

问题:当在 Tester 中使用事件修饰符暴露的委托没有相同的签名时,我会得到一个非常想要且明显的异常,它指出(用我的话)@987654323 @ 不能添加到 Action&lt;int&gt; 的调用列表中。说得通。

为了清楚起见,我正在描述以下内容:

    public event Action<int> On1;    
    public void On1(int i){}

我正在寻找的是一种创建另一个与 EventHandlerType 相同类型的委托的方法。为此,我需要创建一个带有 EventHandlerType 签名 i 的方法,该方法将在内部调用操作。

类似:

 public static void AddHandler(this object obj, Action action)
 {
      var events = obj.GetEvents();
      foreach (var @event in events)
      {
          // method with the signeture of EventHandlerType which does action();
          MethodInfo wrapperMethod = WrapAction(@event.EventHandlerType, action);

          Delegate handler = Delegate.CreateDelegate(@event.EventHandlerType, action.Target, wrapperMethod);
          @event.AddEventHandler(obj, handler);
      }
 }

【问题讨论】:

  • 您想将Action&lt;int&gt; 作为Action 传递并将它们添加到AddHandler 中?
  • 每次调用任何@event 的底层委托时,我都想调用一个动作(是的,为了参数,Action 类型)。我已经描述了我的尝试,但任何解决方案都会受到欢迎。

标签: c# reflection delegates


【解决方案1】:

这似乎可行...里面有各种 cmets...我不确定这是否是最好的方法。我正在构建一个 Expression 树来执行委托调用。

public static void AddHandler(this object obj, Action action)
{
    var events = obj.GetEvents();

    foreach (var @event in events)
    {
        // Simple case
        if (@event.EventHandlerType == typeof(Action))
        {
            @event.AddEventHandler(obj, action);
        }
        else
        {
            // From here: http://stackoverflow.com/a/429564/613130
            // We retrieve the parameter types of the event handler
            var parameters = @event.EventHandlerType.GetMethod("Invoke").GetParameters();

            // We convert it to ParameterExpression[]
            ParameterExpression[] parameters2 = Array.ConvertAll(parameters, x => Expression.Parameter(x.ParameterType));

            MethodCallExpression call;

            // Note that we are "opening" the delegate and using
            // directly the Target and the Method! Inside the 
            // LambdaExpression we will build there won't be a 
            // delegate call, there will be a method call!
            if (action.Target == null)
            {
                // static case
                call = Expression.Call(action.Method);
            }
            else
            {
                // instance type
                call = Expression.Call(Expression.Constant(action.Target), action.Method);
            }

            // If you are OK to create a delegate that calls another
            // delegate, you can:
            // call = Expression.Call(Expression.Constant(action), typeof(Action).GetMethod("Invoke"));
            // instead of the big if/else

            var lambda = Expression.Lambda(@event.EventHandlerType, call, parameters2);
            @event.AddEventHandler(obj, lambda.Compile());
        }
    }
}

【讨论】:

  • 我正在研究一个类似的答案,但你打败了我 :) 很好的实现。
  • 太棒了:) 10x 分配。
猜你喜欢
  • 1970-01-01
  • 2015-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-01
  • 2011-04-07
相关资源
最近更新 更多