2012-03-17 92 views
10

的行動對任何事件類型考慮:訂閱通過反射

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

事件的參數是不相關的,我不需要他們,我不感興趣。我只想讓Foo()被調用。沒有明顯的方式通過反思來做同樣的事情。

我想轉換到上述沿

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

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

線的東西還有,我不想使傳遞給嚴格欄對象的類型堅持準則的前提使用EventHander(TArgs)簽名進行事件。簡而言之,我正在尋找一種方法來訂閱任何處理程序類型的Action;簡單來說,一種將Action委託轉換爲預期處理程序類型的委託的方法。

+4

+1發射導彈! – Jason 2012-03-17 20:18:29

+1

如果用於該事件的委託類型具有非空的返回類型或「out」參數,那麼您會發生什麼情況? – 2012-03-17 20:27:42

+0

@JonSkeet好點,我沒有真正考慮它;輸出參數和返回值對於事件並不真正有用。但我期望轉換錯誤,異常等。基本上我想假設這些類型不會被用作我自己理智的事件處理程序。 – Siege 2012-03-17 20:40:55

回答

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

用法:

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

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

啊,令人困惑,但它的作品!並讓我意識到表達的真棒(我從來沒有理由使用它們)。我沒有徹底地測試過,但我認爲我有我需要的東西。謝謝;) – Siege 2012-03-17 22:53:14

+0

我正在尋找兩天:)謝謝,非常感謝你:))) – 2014-12-11 13:52:50

+0

但我有一個問題。當我將Action更改爲Action =(o,e)=> ...時,它的錯誤可以幫助我解決這個問題嗎? – 2014-12-11 14:02:19

0

這個怎麼樣?

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