【发布时间】:2015-11-03 16:29:16
【问题描述】:
假设我有这个方法:
MethodBuilder doubleMethod = typeBuilder.DefineMethod("Double",
MethodAttributes.Public | MethodAttributes.Static,
typeof(int), new [] { typeof(int) });
ILGenerator il = countMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0); // We load the input argument (an int) into the evaluation stack
il.Emit(OpCodes.Ldc_I4_2); // We load the integer 2 into the evaluation stack
il.Emit(OpCodes.Mul); // We multiply both numbers (n * 2)
il.Emit(OpCodes.Ret); // We return what is left on the evaluation stack, i.e. the result of the multiplication
我可以成功调用这个方法:
Type type = typeBuilder.CreateType();
MethodInfo method = type.GetMethod("Double");
object result = method.Invoke(null, new object[] { 4 }); // result = 8
但是,如果我将我的 IL 代码更改为:
il.Emit(OpCodes.Ldarg_0); // We load the input argument (an int) into the evaluation stack
il.Emit(OpCodes.Ldc_I4_2); // We load the integer 2 into the evaluation stack
il.Emit(OpCodes.Mul); // We multiply both numbers (n * 2)
/* I added these two instructions */
il.Emit(OpCodes.Stloc_0); // We pop the value from the evaluation stack and store into a local variable
il.Emit(OpCodes.Ldloc_0); // We read that local variable and push it back into the evaluation stack
il.Emit(OpCodes.Ret); // We return what is left on the evaluation stack, i.e. the result of the multiplication
尝试调用生成的方法时,抛出以下异常:
TargetInvocationException 未处理 - 调用目标已抛出异常。
这是为什么?我的意思是,从评估堆栈中弹出值然后再次推送相同的值应该什么都不做。当它到达OpCodes.Ret 时,正确的值应该在评估堆栈上。
【问题讨论】:
-
在您对此感到热血沸腾之前,首先要了解如何诊断 TargetInvocationException。您必须查看 InnerException 以找出问题所在。并使用 ILGenerator.DeclareLocal() 以便它可以正确测量所需的堆栈大小。
-
@HansPassant 实际上,内部异常只是声明
"Common Language Runtime detected an invalid program",我认为它太笼统而无法找到相关性,堆栈跟踪似乎也没有帮助。 -
@HansPassant 添加
il.DeclareLocal(typeof(int))成功了!谢谢!您可以将其发布为答案吗? (另外,为什么我需要调用这个方法?)
标签: c# .net reflection cil reflection.emit