Getting useless exceptions is a part of the joy of generating IL code. When you get "Exception has been thrown by the target of an invocation", you can look at the
InnerException property and see if you can get something more useful there:
try myObj.GetType().GetMethod("MyMethod").Invoke(myObj, [|2; 3|]) |> printfn "%A" with e -> printfn "%A" e.InnerException
In this case, the inner exception says:
System.InvalidProgramException: Common Language Runtime detected an invalid program.
This simply means that your generated IL is wrong - I'm afraid you won't get a better error message, but you can save the generated assembly to a disk and run
peverify or Reflector/ILSpy to see how they would interpret the generated code. This means you'll need to add another code path to generate a proper (non-dynamic) assembly, but I think it is worth it - you'll need to debug the generated IL often...
In this case, the problem is that
Ldarg_0 refers to
this (rather than the first argument) and so you need to generate:
ilGen.Emit(OpCodes.Ldarg_1) ilGen.Emit(OpCodes.Ldarg_2) ilGen.Emit(OpCodes.Add) ilGen.Emit(OpCodes.Ret)