Reflection - Add a delegate to another delegate call list

I am trying to attach a delegate to the call list of another delegate. In this way I achieve a kind of Hook on existing events. I need to connect something that fires after every event triggered.

The following example works as long as the delegate opened by type and passing Action i has the same signature. (On1 and OnAll events are declared by the Action delegate, so it works.)

Code: how do I connect an action with an existing delegate subject to the 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); } } } 

Sample:

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

Problem . When a delegate set using the event modifier in the test does not have the same signature, I get a well-thought-out and obvious exception that says (in my opinion) that Action cannot be added to the Action<int> call list . has the meaning.

To be clear, I describe 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 EventHandlerType. To do this, I need to create a method with the signature I EventHandlerType, which will internally trigger an 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); } } 
+8
reflection c # delegates
source share
1 answer

This seems to work ... There are various comments inside ... I'm not sure if this is the best way to do this. I am creating an Expression tree to make a delegate call.

 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()); } } } 
+10
source share

All Articles