lundi 18 mai 2015

Reflection - Add Delegate to another Delegates invocation list

i am attempting to attach a Delegate to an invocation list of a different delegate. By that i am achieving a kind of Hook on existing events. I need to hook up something that runs after each event that is invoked.

The following example works as long as the Delegate exposed by the type and the Action i pass in have the exact same signature.

Code : How i hook up an Action with an existing delegate exposed by an event modifier.

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

The Sample :

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

    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() { }
} 

The Problem : When the Delegate exposed with an event modifier in Tester does not have the same signature i get a well wanted and obvious exception which states (in my words) that Action can't be added to an invocation list of an Action . makes sense.

Just to be clear I'm describing the following :

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

What I'm looking for is a way to create another Delegate of the same type as the EventHandlerType. In order to do that i need to create a method with the signature i of EventHandlerType which would internally invoke action.

something like :

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





Aucun commentaire:

Enregistrer un commentaire