【问题标题】:Dynamic event generation in C# using DynamicMethod and ILGenerator使用 DynamicMethod 和 ILGenerator 在 C# 中生成动态事件
【发布时间】:2009-03-23 18:48:56
【问题描述】:

我需要在运行时基于 EventInfo 对象生成一个事件处理程序,并在该事件处理程序中调用一个方法。类似于以下内容:

public void RegisterAction(ActionData actionData, EventInfo eventInfo, 
    Control control)
{
    MethodInfo methodInfo = eventInfo.EventHandlerType.GetMethod("Invoke");

    List<Type> ps = new List<Type>();
    foreach (ParameterInfo info in methodInfo.GetParameters())
    {
        ps.Add(info.ParameterType);
    }

     DynamicMethod method = new DynamicMethod("Adapter",
                                              typeof (void),
                                              ps.ToArray(),
                                              GetType(), 
                                              true);

     ILGenerator generator = method.GetILGenerator();

     // Here I need to generate a method to do the following:
     // ExecuteAction(actionData);

     // Then I can use this runtime method as an event handler and
     // bind it to the control
     Delegate proxy = method.CreateDelegate(eventInfo.EventHandlerType, this);

     eventInfo.AddEventHandler(control, proxy);
}

我需要帮助来生成注释部分的 IL 代码。

【问题讨论】:

  • 是的。 cmets 中所述的部分(正如 Reed Copsey 提到的)

标签: c# ilgenerator


【解决方案1】:
public void RegisterAction(ActionData actionData, EventInfo eventInfo, 
    Control control)
{
    MethodInfo methodInfo = eventInfo.EventHandlerType.GetMethod("Invoke");

    List<Type> ps = new List<Type>();
    ps.Add  (typeof (ActionData)) ;
    foreach (ParameterInfo info in methodInfo.GetParameters())
    {
        ps.Add(info.ParameterType);
    }

     DynamicMethod method = new DynamicMethod("Adapter",
                                              typeof (void),
                                              ps.ToArray(),
                                              GetType(), 
                                              true);

     // compatible signatures for ExecuteAction
     // (assuming you aren't interested in sender and eventArgs):
     // static void ExecuteAction (ActionData) ;
     // void ActionData.ExecuteAction () ;
     MethodInfo miExecuteAction = <...> ;
     ILGenerator generator = method.GetILGenerator();
     generator.Emit (OpCodes.Ldarg_0) ;
     generator.Emit (OpCodes.Call, miExecuteAction) ;
     generator.Emit (OpCodes.Ret) ;

     // if you want to pass this to ExecuteAction, 
     // you'll need to put it into actionData.
     Delegate proxy = method.CreateDelegate(eventInfo.EventHandlerType, actionData);

     eventInfo.AddEventHandler(control, proxy);
}

编辑:想想看,如果你所有的事件都遵循 (sender, args) 模式,你甚至不需要搞乱 SRE:

public static void Execute<T> (ActionData data, object sender, T args)
    where T : EventArgs
{
    ExecuteAction (data) ;
}

public void RegisterAction (ActionData actionData, EventInfo eventInfo, 
    Control control)
{
    MethodInfo compatibleMethod = typeof (this).GetMethod ("Execute",
        BindingFlags.Static | BindingFlags.Public).MakeGenericMethod (
        eventInfo.EventHandlerType.GetMethod ("Invoke").GetParameters ()[1].ParameterType)) ;
    eventInfo.AddEventHandler (control, 
        Delegate.CreateDelegate (eventInfo.EventHandlerType, actionData,
        compatibleMethod)) ;
}

【讨论】:

  • 建议的解决方案都不起作用:第一个使用生成方法的第一个参数,而不是 RegisterAction 方法中的 actionData。第二个尝试生成带有错误签名的事件:ActionData 不应该是具有 (object, T) 的方法的参数之一
  • 静态方法的第一个参数将通过委托构造函数绑定到目标对象,所以它应该可以正常工作(在我的代码中使用了该技术),虽然我承认我还没有编译并运行这个特定的代码。
  • 我尝试了许多不同的代码,每次它都会抛出“错误绑定到目标方法”。当它到达 CreateDelegate 时。问题是它没有说明原因!
  • 谢谢安东。您对第二个解决方案所做的更改使其工作以及我这边的一个问题:ExecuteAction 位于一个使 GetMethod 返回 null 的泛型类上。至于 SRE 解决方案,在调用时会抛出 CLR bad program exception。但我要使用委托人
【解决方案2】:

我猜你想从你的事件的 MethodInfo 中做一个委托......

如果是这样,here is an article 描述如何解决这个问题。该文章中解释了所需的 IL 代码。

【讨论】:

    猜你喜欢
    • 2012-05-29
    • 2011-02-17
    • 1970-01-01
    • 2015-11-12
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-02
    相关资源
    最近更新 更多