首先,我已经阅读了
Making a CLR/.NET Language Debuggable,但我仍然无法实现这一点.
我编写了一种玩具语言,通过生成Linq表达式,然后调用LambdaExpression#CompileToMethod.大多数这些表达式都附带调试信息,如下所示:
//SmithExpression#InsertDebugInfo Expression InsertDebugInfo(Expression expression,DebugInfo debugInfo) { var column = 1; var debugExpr = Expression.DebugInfo(debugInfo.SymbolDocumentInfo,Info.LineNumber,column,column + 1); return Expression.Block(debugExpr,expression); }
DebugInfo如下所示:
public class DebugInfo { /* arbitrary value from http://www.famkruithof.net/uuid/uuidgen */ public static Guid SmithGuid = new Guid("83c65910-8376-11e2-9e96-0800200c9a66"); public readonly SymbolDocumentInfo SymbolDocumentInfo; public readonly DebugInfoGenerator DebugPdbGenerator; public DebugInfo(String name) { SymbolDocumentInfo = Expression.SymbolDocument(name,SmithGuid); DebugPdbGenerator = DebugInfoGenerator.CreatePdbGenerator(); } }
整个事情都是这样的(你可以忽略关于inits的部分):
public static Action CompileSmithExpression(SmithExpression sexpression,DebugInfo debugInfo,Parameter moduleParameter,Expando module) { AssemblyName assemblyName = new AssemblyName( "RuntimeHelpers.CompileToSmithExpression helper assembly" ); AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( assemblyName,AssemblyBuilderAccess.RunAndSave ); ModuleBuilder moduleBuilder = assemblyBuilder .DefineDynamicModule(assemblyName.Name,"onlyModule.dll"); var debugAttributes = DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations; ConstructorInfo constructor = typeof(DebuggableAttribute) .GetConstructor(new Type[] { typeof(DebuggableAttribute.DebuggingModes) } ); var cab = new CustomAttributeBuilder(constructor,new object[] { debugAttributes }); assemblyBuilder.SetCustomAttribute(cab); moduleBuilder.SetCustomAttribute(cab); TypeBuilder typeBuilder = moduleBuilder.DefineType("MyDynamicType",TypeAttributes.Public); //inits generates expressions that set 'constant' fields to their values. //the call also adds the 'constant' fields to the typeBuilder. //Must call ToArray() to make it run. var inits = FieldInits(sexpression,typeBuilder).ToArray(); var ex = sexpression.ToExpression(debugInfo); var fullDlrExpression = Expression.Block(inits.Append(ex)); var parameters = new ParameterExpression[] { moduleParameter.DlrParameter }; var lambda = Expression.Lambda(fullDlrExpression,parameters); /* Method will take the module as a parameter. */ MethodBuilder meth = typeBuilder.DefineMethod( "MyMethod",MethodAttributes.Public | MethodAttributes.Static,typeof(void),new Type[] { typeof(Expando) } ); lambda.CompileToMethod(meth,debugInfo.DebugPdbGenerator); Type madeType = typeBuilder.CreateType(); return () => madeType.GetMethod("MyMethod").Invoke(null,new Object[] { module }); }
运行代码提供了我想要的异常,但不包含表达式具有的调试信息.我希望它能说出像“< error_immediate,1>”这样的内容.
Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.MissingMemberException: Can't invoke member error of [] [] at (wrapper dynamic-method) object.CallSite.Target (System.Runtime.CompilerServices.Closure,System.Runtime.CompilerServices.CallSite,Smith.Expando) <IL 0x0004f,0x00127> at System.Dynamic.UpdateDelegates.UpdateAndExecute1<Smith.Expando,object> (System.Runtime.CompilerServices.CallSite,Smith.Expando) <0x0040b> at MyDynamicType.MyMethod (Smith.Expando) <IL 0x002bc,0x00aaa> at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&) <IL 0x00016,0x00067> etc...
我最好的猜测是调试信息确实在那里,但是我必须做更多的工作来让stacktrace显示它.有任何想法吗?
解决方法
您的异常是嵌套异常.要打印出堆栈跟踪,请查看InnerException.
catch (Exception ex) { while (ex != null) { Debug.Print(ex.ToString()); ex = ex.InnerException(); } }