Чтобы сделать 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
s и вызова методов Bind*
для создания дерева выражений самостоятельно.
Все это делается во внешнем слое DLR / IronPython / IronRuby - все доступно на ironpython.codeplex.com . Вы можете посмотреть на CompilerHelpers.CompileToMethod
как пример выполнения компиляции, класс Snippets
(и связанные классы AssemblyGen
/ TypeGen
/ ILGen
для создания отлаживаемых сборок и даже компилятор дерева выражений DLR ( в Runtime\Microsoft.Scripting.Core\Compiler
) для примера выдачи информации о строке.