3
让我们假设我有这样的方法:为什么存储一个局部变量并将其读回触发TargetInvocationException?
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实际上,内部异常只是声明'“公共语言运行时检测到一个无效的程序”,我认为它太泛化了,以至于找不到相关的东西,堆栈跟踪也没有任何帮助。 –
@HansPassant添加'il.DeclareLocal(typeof(int))'诀窍!谢谢!你可以张贴它作为一个水管? (另外,为什么我需要调用此方法?) –