我们正在使用System.Reflection.Emit在源代码中从源代码生成代码(是的 - 在编译器中)。我们使用MarkSequencePoint等向ILGenerator提供正确的符号信息,并启用AssemblyBuilder上的所有调试标志。程序集在编译它的同一进程中保存在内存中,并直接执行。
当使用Visual Studio调试器逐步完成动态生成代码的源代码时,它实际上工作得很好,而Visual Studio似乎完全了解代码来自文件和行号的位置。
但是 - 当生成的代码抛出 exceptions 时,System.Exception对象包含完全错误的堆栈跟踪。它们指向其他(有效但错误的)文件和行号。它获取了类和方法名称,但指向的文件和行号与实例异常的代码路径无关。
指向的文件是如此无关,似乎无法链接到内联或优化。我能看到的唯一模式是它似乎被一些文件所抵消(在一个假想的按字母顺序排序的源文件列表中,汇编是从中构建的)。但是,这种模式并非100%一致,而且与问题的根源相关联似乎是不合理的。
如果我从Exception构造一个System.Diagnostics.Debug对象,它包含相同的错误信息。
我假设.NET运行时使用相同的元数据来构造Exception堆栈跟踪,就像调试器用于单步执行代码一样,在这种情况下,这种行为非常奇怪。
在尝试处理动态内存中的程序集时,或者是否有人在其他方面遇到类似问题时,我试图找出这是否是.NET中的已知错误。
答案 0 :(得分:2)
好吧,我无法弄清楚导致问题的原因以及如何使.NET正常运行,但至少我能够找到一种可能对遇到同样问题的其他人有用的解决办法。 / p>
当我生成CIL字节码时,我正在构建一个单独的数据库,将方法名称(完整路径)和IL偏移映射回原始文件名和行号。
当捕获异常时,我会检查堆栈跟踪并仅使用堆栈帧对象中的GetMethod()
和GetILOffset()
信息。即使GetFileName()
和GetFileLineNumber()
错误,CLR中的这些信息也是正确的。
然后我为每个堆栈帧使用从异常中检索的方法名称和IL偏移量来查找我生成的数据库,以确定每个堆栈帧的实际文件名和行号,我有关于的信息。
我在数据库中找不到相关信息的帧通常是预编译.NET模块中的堆栈帧,从CLR检索的信息实际上是正确的。对于这些帧,我直接在堆栈帧上使用GetFileName()
和GetFileLineNumber()
。