通过反射为任何事件类型订阅操作

got*_*pie 11 .net c# reflection events delegates

考虑:

someControl.Click += delegate { Foo(); };
Run Code Online (Sandbox Code Playgroud)

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

我想将上述内容翻译成类似的内容

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

void Bar(object obj, EventInfo info)
{
    Action callFoo = Foo;
    info.AddEventHandler(obj, callFoo);
}
Run Code Online (Sandbox Code Playgroud)

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

Ser*_*-Tm 8

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);
}
Run Code Online (Sandbox Code Playgroud)

用法:

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

  foreach (var eventInfo in form.GetType().GetEvents())
  {
    AddEventHandler(eventInfo, form, action);
  }
Run Code Online (Sandbox Code Playgroud)