基本上,我接受事件名称作为一个字符串,以获得 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.