2012-03-17 31 views
10

xem xét:Đăng ký một hành động cho bất kỳ loại sự kiện thông qua phản ánh

someControl.Click += delegate { Foo(); }; 

Những lập luận về sự kiện này là không thích hợp, tôi không cần họ và tôi không quan tâm đến họ. Tôi chỉ muốn Foo() được gọi. Không có cách rõ ràng để làm tương tự thông qua sự phản ánh.

Tôi muốn dịch trên vào một cái gì đó dọc theo dòng của

void Foo() { /* launch missiles etc */ } 

void Bar(object obj, EventInfo info) 
{ 
    Action callFoo = Foo; 
    info.AddEventHandler(obj, callFoo); 
} 

Ngoài ra, tôi không muốn làm cho giả định rằng các loại đối tượng truyền cho Bar nghiêm chỉnh tuân thủ các nguyên tắc của sử dụng ký hiệu EventHander (TArgs) cho các sự kiện. Nói một cách đơn giản, tôi đang tìm cách đăng ký một hành động cho bất kỳ loại trình xử lý nào; ít đơn giản hơn, một cách để chuyển đổi ủy nhiệm Hành động thành một đại biểu của loại trình xử lý dự kiến.

+4

+1 Để khởi chạy missles! – Jason

+1

Bạn sẽ mong đợi điều gì xảy ra nếu loại đại biểu được sử dụng cho sự kiện có loại trả về không có giá trị hoặc tham số 'out'? –

+0

@JonSkeet Điểm tốt, tôi đã không thực sự xem xét nó; các tham số và giá trị trả lại không thực sự hữu ích cho các sự kiện. Nhưng tôi sẽ mong đợi một lỗi chuyển đổi, một ngoại lệ, vv Về cơ bản tôi muốn giả định rằng những loại đó sẽ không được sử dụng như trình xử lý sự kiện cho sự tỉnh táo của riêng tôi. – Siege

Trả lời

7
static void AddEventHandler(EventInfo eventInfo, object item, Action action) 
{ 
    var parameters = eventInfo.EventHandlerType 
    .GetMethod("Invoke") 
    .GetParameters() 
    .Select(parameter => Expression.Parameter(parameter.ParameterType)) 
    .ToArray(); 

    var handler = Expression.Lambda(
     eventInfo.EventHandlerType, 
     Expression.Call(Expression.Constant(action), "Invoke", Type.EmptyTypes), 
     parameters 
    ) 
    .Compile(); 

    eventInfo.AddEventHandler(item, handler); 
} 
static void AddEventHandler(EventInfo eventInfo, object item, Action<object, EventArgs> action) 
{ 
    var parameters = eventInfo.EventHandlerType 
    .GetMethod("Invoke") 
    .GetParameters() 
    .Select(parameter => Expression.Parameter(parameter.ParameterType)) 
    .ToArray(); 

    var invoke = action.GetType().GetMethod("Invoke"); 

    var handler = Expression.Lambda(
     eventInfo.EventHandlerType, 
     Expression.Call(Expression.Constant(action), invoke, parameters[0], parameters[1]), 
     parameters 
    ) 
    .Compile(); 

    eventInfo.AddEventHandler(item, handler); 
} 

Cách sử dụng:

Action action =() => BM_21_Grad.LaunchMissle(); 

    foreach (var eventInfo in form.GetType().GetEvents()) 
    { 
    AddEventHandler(eventInfo, form, action); 
    } 
+0

Ah, khó hiểu, nhưng nó hoạt động! Và làm cho tôi nhận ra sự khiếp sợ của các biểu thức (tôi chưa bao giờ có lý do để sử dụng chúng). Tôi đã không thử nghiệm kỹ lưỡng nhưng tôi nghĩ rằng tôi có những gì tôi cần. Cảm ơn;) – Siege

+0

Tôi đã tìm kiếm trong hai ngày :) Cảm ơn bạn, cảm ơn bạn rất nhiều :))) –

+0

Nhưng tôi có một câu hỏi. Khi tôi thay đổi hành động để hành động <đối tượng, EventArg> = (o, e) => ..., lỗi của nó .. Bạn có thể giúp tôi về câu hỏi này? –

0

Làm thế nào về điều này?

void Bar(object obj, EventInfo info) 
{ 
    var parameters = info.EventHandlerType.GetMethod("Invoke").GetParameters() 
     .Select(p => Expression.Parameter(p.ParameterType)); 

    var handler = Expression.Lambda(
     info.EventHandlerType, 
     Expression.Call(
      Expression.Constant(obj), // obj is the instance on which Foo() 
      "Foo",     // will be called 
      null 
     ), 
     parameters 
    ); 
    info.AddEventHandler(obj, handler.Compile()); 
} 
Các vấn đề liên quan