First I must aplogise for being a noob with IL.
I am having difficulty generating IL code to call a method with this signature:
public void CallMethod2(string name, object[] args, object[] genericArgs)
I am able to call a method that has a single array that looks like this:
public void CallMethod1(string name, object[] args)
using the following IL works:
ILGenerator ilgen = myMethod.GetILGenerator();
var il = ilgen;
MethodInfo invokerMethod = typeof(Proxy<T>).GetMethod("CallMethod1", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, method.Name);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Newarr, typeof(System.Object));
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg, 1);
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Call, invokerMethod);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ret);
But then I use the following IL to try and call CallMethod2 using this IL:
ILGenerator ilgen = myMethod.GetILGenerator();
var il = ilgen;
MethodInfo invokerMethod = typeof(Proxy<T>).GetMethod("CallMethod2", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, method.Name);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Newarr, typeof(System.Object));
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg, 1);
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Newarr, typeof(System.Object));
il.Emit(OpCodes.Stloc_1);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ldarg, 1);
il.Emit(OpCodes.Stelem_Ref);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ldloc_2);
il.Emit(OpCodes.Call, invokerMethod);
il.Emit(OpCodes.Nop);
il.Emit(OpCodes.Ret);
This IL with additional object[] I get an error:
Common Language Runtime detected an invalid program.
As you can see all i did was added the 2nd block to populate the array and call the method, it seems that by using StLoc_1 it just corrupts it.
I wrote the same method and called it normally and looked at ILDasm and the codes seem to all tie up.
Thanks
I’m very confused… you see: that code shouldn’t work since you haven’t actually allocated any locals; for example, here’s a badly written (in that it uses unnecessary locals) multiply-by-4 method, that doesn’t declare the locals:
This creates the
VerificationException:since it is unverifiable. It is bad IL! If we change it to:
then now it works. This then leads onto an alternative to remembering the numbers – by storing and using the
LocalBuilderthat is returned fromDeclareLocal:If you are concerned that this uses the longer IL version, then you can use instead:
along with
il.LoadLocal(multiplier);andil.LoadLocal(result);(and obviously something similar forStloc)