尝试调试发出错误,是否有一种简单的方法来查找有关异常的更多信息由发出的代码引起的?
例如,使用下面的代码:
let dynamicAssembly =
let asmName = new AssemblyName("MyAsm")
let asmBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run)
let moduleBuilder = asmBuilder.DefineDynamicModule("MyModule")
let typeBuilder = moduleBuilder.DefineType("MyDynamicType")
let methodBuilder =
let build = typeBuilder.DefineMethod("MyMethod", MethodAttributes.Public,
CallingConventions.Standard,
typeof<Int32>,
[|typeof<Int32>; typeof<Int32>|])
let ilGen = build.GetILGenerator()
ilGen.Emit(OpCodes.Ldarg_0)
ilGen.Emit(OpCodes.Ldarg_1)
ilGen.Emit(OpCodes.Add)
ilGen.Emit(OpCodes.Ret)
typeBuilder.CreateType() |> ignore
asmBuilder
let myType = dynamicAssembly.GetType("MyDynamicType")
let myObj = Activator.CreateInstance(myType)
myObj.GetType().GetMethod("MyMethod").Invoke(myObj, [|2; 3|]) |> ignore
我得到"异常已被调用的目标抛出。当我试着在倒数第二行拨打Invoke
时。发出代码总是有问题,但如果我能弄清楚如何获得有意义的异常,可能就不那么痛苦了。想法吗?
获取无用的异常是生成IL代码的乐趣之一。当你得到"异常已经被调用的目标抛出"时,你可以查看InnerException
属性,看看你是否能在那里得到一些更有用的东西:
try
myObj.GetType().GetMethod("MyMethod").Invoke(myObj, [|2; 3|]) |> printfn "%A"
with
e -> printfn "%A" e.InnerException
在这种情况下,内部异常说:
系统。InvalidProgramException:公共语言运行库检测到一个无效程序。
这仅仅意味着你生成的IL是错误的-恐怕你不会得到一个更好的错误信息,但你可以将生成的程序集保存到磁盘上,并运行peverify
或Reflector/ILSpy,看看他们如何解释生成的代码。这意味着您需要添加另一个代码路径来生成适当的(非动态)程序集,但我认为这是值得的-您需要经常调试生成的IL…
在这种情况下,问题是Ldarg_0
引用this
(而不是第一个参数),因此您需要生成:
ilGen.Emit(OpCodes.Ldarg_1)
ilGen.Emit(OpCodes.Ldarg_2)
ilGen.Emit(OpCodes.Add)
ilGen.Emit(OpCodes.Ret)