あなたは何が何であるかを理解していませんでしたSymbolDocument()
...
var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("foo"), System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave);
var mod = asm.DefineDynamicModule("mymod", true);
var type = mod.DefineType("baz", TypeAttributes.Public);
var method = type.DefineMethod("go", MethodAttributes.Public | MethodAttributes.Static);
Expression fooExpression = Expression.Divide(Expression.Constant(0), Expression.Constant(0));
var parameters = new ParameterExpression[0];
var generator = DebugInfoGenerator.CreatePdbGenerator();
var document = Expression.SymbolDocument(fileName: "MyDebug.txt");
var debugInfo = Expression.DebugInfo(document, 6, 9, 6, 22);
var expressionBlock = Expression.Block(debugInfo, fooExpression);
var lambda = Expression.Lambda(expressionBlock, parameters);
lambda.CompileToMethod(method, generator);
var bakedType = type.CreateType();
Func<int> method2 = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), bakedType.GetMethod(method.Name));
try
{
int res = method2();
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
}
Expression
私が生成したのは のようなものreturn 0/0;
です。私はそれを実行し、例外をトラップします (メソッドは をとして配置するInvoke
ため、メソッドを使用しないことに注意してください)。Invoke
DivisionByZeroException
InnerException
私が出力したスタック トレースは次のようなものです。
MyDebug.txt の baz.go() で: ConsoleApplication85.Program.Test() の行 6
6が見えMyDebug.txt:row
ますか?彼らはあなたSymbolDocument
とあなたDebugInfo
です。
Debugging Dynamically Generated Code (Reflection.Emit)からのより完全な例。
static void Test()
{
// create a dynamic assembly and module
AssemblyName assemblyName = new AssemblyName("HelloWorld");
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
// Mark generated code as debuggable.
// See https://docs.microsoft.com/en-us/archive/blogs/rmbyers/debuggableattribute-and-dynamic-assemblies for explanation.
Type daType = typeof(DebuggableAttribute);
ConstructorInfo daCtor = daType.GetConstructor(new Type[] { typeof(DebuggableAttribute.DebuggingModes) });
CustomAttributeBuilder daBuilder = new CustomAttributeBuilder(daCtor, new object[] {
DebuggableAttribute.DebuggingModes.DisableOptimizations |
DebuggableAttribute.DebuggingModes.Default });
assemblyBuilder.SetCustomAttribute(daBuilder);
ModuleBuilder module = assemblyBuilder.DefineDynamicModule("HelloWorld.exe", true); // <-- pass 'true' to track debug info.
var doc = Expression.SymbolDocument(@"Source.txt");
// create a new type to hold our Main method
TypeBuilder typeBuilder = module.DefineType("HelloWorldType", TypeAttributes.Public | TypeAttributes.Class);
// create the Main(string[] args) method
MethodBuilder methodbuilder = typeBuilder.DefineMethod("MyMethod", MethodAttributes.HideBySig | MethodAttributes.Static | MethodAttributes.Public, typeof(void), new Type[] { typeof(string[]) });
// Create a local variable of type 'string', and call it 'xyz'
var localXYZ = Expression.Variable(typeof(string), "xyz"); // Provide name for the debugger.
var generator = DebugInfoGenerator.CreatePdbGenerator();
var debugInfo1 = Expression.DebugInfo(doc, 2, 1, 2, 100);
// Emit sequence point before the IL instructions. This is start line, start col, end line, end column,
// Line 2: xyz = "hello";
var assign = Expression.Assign(localXYZ, Expression.Constant("Hello world!"));
// Line 3: Write(xyz);
MethodInfo infoWriteLine = typeof(System.Console).GetMethod("WriteLine", new Type[] { typeof(string) });
var debugInfo2 = Expression.DebugInfo(doc, 3, 1, 3, 100);
var write = Expression.Call(infoWriteLine, localXYZ);
// Line 4: return;
var debugInfo3 = Expression.DebugInfo(doc, 4, 1, 4, 100);
var block = Expression.Block(new ParameterExpression[] { localXYZ }, new Expression[] { debugInfo1, assign, debugInfo2, write, debugInfo3 });
var lambda = Expression.Lambda<Action<string[]>>(block, Expression.Parameter(typeof(string[])));
// bake it
lambda.CompileToMethod(methodbuilder, generator);
Type helloWorldType = typeBuilder.CreateType();
// This now calls the newly generated method. We can step into this and debug our emitted code!!
var dm = (Action<string[]>)Delegate.CreateDelegate(typeof(Action<string[]>), helloWorldType.GetMethod("MyMethod"));
dm(new string[] { null }); // <-- step into this call
}
これを Source.txt としてどこかに保存します
1| // Test
2| xyz = "hello";
3| Write(xyz);
4| return;
次に、にブレークポイントを置き、dm(new string[] { null })
bp で F11 を押します。を求められますSource.txt
。選択しない場合、もう一度.suo
ウィンドウを取得するにはファイルを削除する必要があることに注意してください。
の使用に注意してくださいDebuggableAttribute
。動的アセンブリをデバッグ可能としてマークするのがトリックのようです。