2012-03-17 111 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()); 
}