mardi 3 novembre 2015

Reflection.Emit - Why does storing a local variable and reading it back triggers a TargetInvocationException?

Let's suppose I have this method:

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

I can call this method successfully:

Type type = typeBuilder.CreateType();
MethodInfo method = type.GetMethod("Double");
object result = method.Invoke(null, new object[] { 4 }); // result = 8

However, If I change my IL code to this:

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 

When trying to call the generated method, the following exception is thrown:

TargetInvocationException was unhandled - Exception has been thrown by the target of an invocation.

Why is this? I mean, popping the value from the evaluation stack and then pushing the same value again should do absoultely nothing. By the time it reaches OpCodes.Ret, the correct value should be on the evaluation stack.





Aucun commentaire:

Enregistrer un commentaire