gpt4 book ai didi

c# - IL Emit 调用委托(delegate)实例?

转载 作者:太空狗 更新时间:2023-10-29 21:15:42 26 4
gpt4 key购买 nike

基本上,我接受事件名称作为字符串,以获取 EventInfo。然后,我使用反射发现事件处理程序类型和事件参数类型,创建该类型的新委托(delegate) (myEventHandler),并将其与事件 Hook 。每当调用 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 });

编辑:基于通过 Reflector 的观察。

反射器为手动编码场景生成的代码是

.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);

但这会导致运行时错误:

'Calling convention must be varargs'

可能我遗漏了什么,需要更好地了解 IL。

最佳答案

好的 - 这可能会有所帮助;它生成 IL 以在委托(delegate)类型之间切换,只要它们匹配标准模式。它仅在必要时添加一个 castclass(因此,如果您要从 MouseEventArgs 转到 EventArgs,则没有必要,但在相反的方向上是必要的)。由于您显然在使用反射,所以我没有使用泛型(这会使事情变得更难)。

厚脸皮的一点是,它没有使用捕获类,而是假装该方法属于我要捕获的数据,并将状态用作arg0。我无法确定它是邪恶还是聪明,所以我会选择“clevil”。

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
using System.Windows.Forms;

class Program {
static ParameterInfo[] VerifyStandardHandler(Type type) {
if (type == null) throw new ArgumentNullException("type");
if (!typeof(Delegate).IsAssignableFrom(type)) throw new InvalidOperationException();
MethodInfo sig = type.GetMethod("Invoke");
if (sig.ReturnType != typeof(void)) throw new InvalidOperationException();
ParameterInfo[] args = sig.GetParameters();
if (args.Length != 2 || args[0].ParameterType != typeof(object)) throw new InvalidOperationException();
if (!typeof(EventArgs).IsAssignableFrom(args[1].ParameterType)) throw new InvalidOperationException();
return args;
}
static int methodIndex;
static Delegate Wrap(Delegate value, Type type) {
ParameterInfo[] destArgs = VerifyStandardHandler(type);
if (value == null) return null; // trivial
if (value.GetType() == type) return value; // already OK
ParameterInfo[] sourceArgs = VerifyStandardHandler(value.GetType());
string name = "_wrap" + Interlocked.Increment(ref methodIndex);
Type[] paramTypes = new Type[destArgs.Length + 1];
paramTypes[0] = value.GetType();
for (int i = 0; i < destArgs.Length; i++) {
paramTypes[i + 1] = destArgs[i].ParameterType;
}
DynamicMethod dyn = new DynamicMethod(name, null, paramTypes);
MethodInfo invoker = paramTypes[0].GetMethod("Invoke");
ILGenerator il = dyn.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_2);
if (!sourceArgs[1].ParameterType.IsAssignableFrom(destArgs[1].ParameterType)) {
il.Emit(OpCodes.Castclass, sourceArgs[1].ParameterType);
}
il.Emit(OpCodes.Call, invoker);
il.Emit(OpCodes.Ret);
return dyn.CreateDelegate(type, value);
}
static void Main() {
EventHandler handler = delegate(object sender, EventArgs eventArgs) {
Console.WriteLine(eventArgs.GetType().Name);
};
MouseEventHandler wrapper = (MouseEventHandler)Wrap(handler, typeof(MouseEventHandler));
MouseEventArgs ma = new MouseEventArgs(MouseButtons.Left, 1, 1, 1, 1);
wrapper(new object(), ma);

EventHandler backAgain = (EventHandler)Wrap(wrapper, typeof(EventHandler));
backAgain(new object(), ma);
}
}

显然,您仍然需要使用常规方法(Delegate.CreateDelegate 等)为事件生成委托(delegate),但您可以随后将其包装到 EventHandler 中,或者反转。

关于c# - IL Emit 调用委托(delegate)实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1813268/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com