【发布时间】:2009-11-28 18:18:08
【问题描述】:
基本上,我接受事件名称作为字符串,以获取EventInfo。然后,我使用反射发现事件处理程序类型和事件参数类型,创建该类型的新委托 (myEventHandler),并将其与事件挂钩。当myEventHandler 被调用时,我需要向下转换并将参数传递给处理程序。
我的代码如下。当调用“d”时,需要通过myEventHandler 调用“处理程序”。我需要在放置 ??? 的地方放一些反射发射代码。有什么想法吗?
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 });
编辑:基于通过反射器的观察。
手动编码场景的反射器生成代码是
.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
}
这就是我基于此尝试的。
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);
但这会导致运行时错误:
'调用约定必须是可变参数'
可能我遗漏了一些东西,需要更好地了解 IL。
【问题讨论】:
-
这里的诀窍总是简单地用 C# 编写你想要的代码并使用反射器/ILDASM 来查看 IL。我猜想是 ld、castclass 和 callvirt 的组合
-
是的,同意。我会走那条路,但认为 SO 中的任何反射发射忍者都可能很快指出这一点
-
再看 - “处理程序”驻留在哪里?相对于参数?我认为将两者结合起来会很痛苦。看起来 C# 版本使用了一个捕获类,但是你现在的动态方法是静态的,所以无处可推任何状态......
标签: c# .net reflection reflection.emit