2015-05-18 15 views
8

tôi đang cố gắng đính kèm Đại biểu vào danh sách yêu cầu của một đại biểu khác. Bằng cách đó tôi đang đạt được một loại Hook về các sự kiện hiện có. Tôi cần kết nối một thứ gì đó chạy sau mỗi sự kiện được gọi.Phản ánh - Thêm đại biểu vào danh sách yêu cầu của đại biểu khác

Ví dụ sau hoạt động miễn là Đại biểu tiếp xúc theo loại và Hành động i vượt qua có cùng chữ ký chính xác. (Các sự kiện On1 và OnAll đều được khai báo với một đại biểu Hành động để nó hoạt động).

Mã: Cách tôi kết thúc Hành động với đại biểu hiện tại được tiếp xúc bởi công cụ sửa đổi sự kiện.

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

Các mẫu:

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

Vấn đề: Khi các đại biểu tiếp xúc với một sửa đổi sự kiện trong Tester không có chữ ký cùng tôi nhận được một ngoại lệ cũng muốn và rõ ràng trong đó nêu (trong lời nói của tôi) rằng không thể thêm Action vào danh sách yêu cầu của số Action<int>. có ý nghĩa.

Chỉ cần được rõ ràng tôi đang mô tả như sau:

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

Những gì tôi đang tìm kiếm là một cách để tạo ra một Đại biểu cùng loại như EventHandlerType. Để làm được điều đó, tôi cần tạo một phương thức có chữ ký i của EventHandlerType để gọi nội bộ hành động.

cái gì đó như:

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

Bạn muốn chuyển 'Action ' làm 'Hành động' và thêm chúng vào' AddHandler'? –

+0

Tôi muốn gọi một hành động (có loại Hành động vì lợi ích của đối số) mỗi lần bất kỳ ủy nhiệm cơ bản của sự kiện @ được gọi. Ive mô tả những gì tôi đã cố gắng nhưng giải pháp nào sẽ được chào đón nhiều nhất. –

Trả lời

10

Điều này dường như làm việc ... Có ý kiến ​​khác nhau bên trong ... Tôi không chắc chắn nếu điều này là cách tốt nhất để làm điều đó. Tôi đang xây dựng cây Expression để thực hiện yêu cầu ủy quyền.

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()); 
     } 
    } 
} 
+0

Tôi đã làm việc trên một câu trả lời tương tự nhưng bạn đánh bại tôi với nó :) thực hiện tuyệt vời. –

+0

có vẻ tốt cho phép tôi dùng thử. –

+0

Amazing :) 10x allot. –

Các vấn đề liên quan