IL的Emit用于调用委托实例?实例、IL、Emit

2023-09-03 05:24:18 作者:爷、你惹不起

基本上,我接受事件名称作为一个字符串,以获得 EventInfo 。然后,我发现使用反射事件处理程序的类型和事件参数类型,创建类型( myEventHandler )的新代表,并与该事件挂钩起来。当过 myEventHandler 被调用,我需要向下转换和传递参数给处理程序。

Basically, I'm accepting an event name as a string, to get the EventInfo. Then, I'm discovering the event handler type and event argument type using reflection, creating a new delegate of that type (myEventHandler), and hooking it up with the event. When ever myEventHandler is invoked, I need to downcast and pass the arguments to the handler.

我的code是如下。该处理程序需要通过 myEventHandler 来调用,D被调用时直到永远。我需要有一些反射发出code那里有我把???。有什么想法?

My code is as below. The 'handler' needs to be invoked via myEventHandler, when ever 'd' is invoked. I need to have some Reflection emit code there where I put ???. Any thoughts?

EventHandler handler = delegate(object sender, EventArgs eventArgs)
{
    //something will happen here                                
};

Type[] typeArgs = { typeof(object), derivedEventArgsType };

DynamicMethod myEventHandler = new DynamicMethod("", typeof(void), typeArgs);
var ilgen = myEventHandler.GetILGenerator();

//What should be the IL code here to 
//cast derviedEventArgs to EventArgs and
//invoke the 'handler' above??????
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ret);



Delegate d = dynamic.CreateDelegate(derviedEventHandlerType);

//addMethod is the add MethodInfo for an Event
addMethod.Invoke(target, new object[] { d });

编辑:基于通过反射观察

反射器产生的code对于手动codeD的情况是

The reflector generated code for a manually coded scenario is

.method public hidebysig instance void <Main>b__1(object sender, class ConsoleApplication2.MyEventArgs e) cil managed
{
    .maxstack 8
    L_0000: nop 
    L_0001: ldarg.0 
    L_0002: ldfld class [mscorlib]System.EventHandler ConsoleApplication2.Program/<>c__DisplayClass3::handler
    L_0007: ldarg.1 
    L_0008: ldarg.2 
    L_0009: callvirt instance void [mscorlib]System.EventHandler::Invoke(object, class [mscorlib]System.EventArgs)
    L_000e: nop 
    L_000f: ret 
}

这是我试过的基础上。

And this is what I tried based on that.

ilgen.Emit(OpCodes.Nop); 
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld,eh.GetType().GetField("handler"));
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Ldarg_2);
ilgen.EmitCall(OpCodes.Callvirt,eh.handler.Method,
               new Type[]{ typeof(object), typeof(EventArgs) });
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ret);

但是,这是造成运行时错误:

调用约定必须是可变参数

'Calling convention must be varargs'

也许我失去了一些东西,需要有一个更美好的期待成IL。

Probably I'm missing something, need to have a better look into IL.

推荐答案

原来我是大大过于复杂的事情!巴里·凯利是对的:

It turns out I was vastly over-complicating things! Barry Kelly had the right idea:

static T CastDelegate<T>(Delegate src)
    where T : class
{
    return (T)(object)Delegate.CreateDelegate(
        typeof(T),
        src.Target,
        src.Method,
        true); // throw on fail
}

这是适合我的测试用例。

That works for my test cases.