通过反射将 Action 订阅到任何事件类型 [英] Subscribing an Action to any event type via reflection

查看:19
本文介绍了通过反射将 Action 订阅到任何事件类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑:

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

事件的参数无关紧要,我不需要它们,我对它们不感兴趣.我只是想让 Foo() 被调用.没有明显的方法可以通过反射来做同样的事情.

The arguments of the event are irrelevant, I don't need them and I'm not interested in them. I just want Foo() to get called. There's no obvious way to do the same via reflection.

我想将以上内容翻译成类似

I'd like to translate the above into something along the lines of

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

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

另外,我不想假设传递给 Bar 的对象类型严格遵守对事件使用 EventHander(TArgs) 签名的准则.简而言之,我正在寻找一种将 Action 订阅到任何处理程序类型的方法;不太简单,一种将 Action 委托转换为预期处理程序类型的委托的方法.

Also, I don't want to make the assumption that the type of object passed to Bar strictly adheres to the guidelines of using the EventHander(TArgs) signature for events. To put it simply, I'm looking for a way to subscribe an Action to any handler type; less simply, a way to convert the Action delegate into a delegate of the expected handler type.

推荐答案

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

这篇关于通过反射将 Action 订阅到任何事件类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆