因此,这实际上是两个问题: 1. 我该如何使IL可调试? 2. 我该如何使DLR调用站点可调试?
非常感谢您的帮助!
“调试性”方面我所需要的:
在附加的Visual Studio实例中: 1. 逐步执行代码 2. 查看本地变量 3. 查看堆栈跟踪
要使IL可调试,需要将代码编译成可调试的程序集。但是这样做会有一个明显的缺点,即程序集将无法被GC收集。为了实现这一点,您可以使用 AppDomain.CurrentDomain.DefineDynamicAssembly
方法创建一个动态程序集,然后调用 DefineDynamicModule
方法在程序集中定义一个模块。为了使其可调试,您需要在模块上设置一些属性:
DebuggableAttribute.DebuggingModes attrs =
DebuggableAttribute.DebuggingModes.Default |
DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints |
DebuggableAttribute.DebuggingModes.DisableOptimizations;
Type[] argTypes = new Type[] { typeof(DebuggableAttribute.DebuggingModes) };
Object[] argValues = new Object[] { attrs };
_myAssembly.SetCustomAttribute(new CustomAttributeBuilder(
typeof(DebuggableAttribute).GetConstructor(argTypes), argValues)
);
_myModule.SetCustomAttribute(new CustomAttributeBuilder(
typeof(DebuggableAttribute).GetConstructor(argTypes), argValues)
);
在发出IL指令时,最后调用MarkSequencePoint
来标记以下IL指令的行。
让DLR调用站点可调试对我来说有些奇怪 - 通常你的调用站点不会包含任何用户代码。相反,它将包含执行操作的代码,并且与该代码相关联的没有源代码。但假设您真的希望有一些与您为调用站点生成的表达式树相关联可以逐步执行的东西。要做到这一点,您需要完成两件事。首先是在表达式树中存储调试信息-使用DebugInfoExpression
实现此目的。接下来是将方法编译为可调试的方法并将其委托提供给DLR。
要编译方法,您需要使用LambdaExpression<T>.CompileToMethod
。您需要提供的MethodBuilder
将需要是在您之前创建的可调试程序集中定义的某个类型中的静态方法。
要将该委托提供给DLR,您有两个选择。可能最简单的方法是实际上返回一个表达式,该表达式调用已编译的可调试委托(仅通过常量保留它)。但在某些方面更优雅的更困难的方法将覆盖调用站点上的BindDelegate<T>
并返回已编译的委托。然而,这需要创建适当的参数Expression
并调用Bind*
方法来自己生成表达式树。
所有这些都是在DLR外层/IronPython/IronRuby中完成的-全部可在ironpython.codeplex.com找到。您可以查看CompilerHelpers.CompileToMethod
作为编译示例,Snippets
类(以及用于创建可调试程序集的关联AssemblyGen
/TypeGen
/ILGen
类),甚至DLR表达式树编译器(位于Runtime\Microsoft.Scripting.Core\Compiler
)作为发射行信息的示例。