12

System.Reflection.Emit を使用して、実行時にソース コードからコードを生成しています (はい - コンパイラのように)。MarkSequencePoint などを使用して ILGenerator に正しいシンボル情報を提供し、AssemblyBuilder ですべてのデバッグ フラグを有効にします。アセンブリは、それをコンパイルしたのと同じプロセスでメモリに保持され、直接実行されます。

Visual Studio デバッガーを使用して動的に生成されたコードのソースをステップ実行すると、実際には完全に機能し、Visual Studio はファイルと行番号に関してコードがどこから来たのかを完全に認識しているようです。

HOWEVER -生成されたコードによって例外がスローされると、System.Exception オブジェクトには完全に間違ったスタック トレースが含まれます。それらは、他の (有効だが間違った) ファイルと行番号を指しています。クラスとメソッド名は正しく取得されますが、ポイントされているファイルと行番号は、実際に例外が発生したコード パスとは何の関係もありません。

指摘されたファイルは無関係であるため、インライン化または最適化にリンクできないようです。私が見つけることができる唯一のパターンは、いくつかのファイルによってオフセットされているように見えることです (アセンブリが構築された元のソース ファイルのアルファベット順に並べ替えられた架空のリスト内)。ただし、このパターンは 100% 一貫しているわけではなく、これが問題の原因に関連しているとは思えません。

例外から System.Diagnostics.Debug オブジェクトを構築すると、同じエラー情報が含まれます。

.NET ランタイムは、デバッガーがコードのステップ実行に使用するものと同じメタデータを使用して例外スタック トレースを作成すると想定しています。この場合、この動作は非常に奇妙です。

これが動的なインメモリ アセンブリを処理する際の .NET の既知のバグであるかどうか、または他の領域で同様の問題が発生したことがあるかどうかを調べようとしています。

4

1 に答える 1

2

問題の原因も、.NET を正しく動作させる方法もわかりませんでしたが、少なくとも、同じ問題を経験している他のユーザーにも有効な回避策を見つけることができました。

  1. CIL バイトコードを生成しているので、メソッド名 (フル パス) と IL オフセットを元のファイル名と行番号にマップする別のデータベースを構築しています。

  2. 例外がキャッチされると、スタック トレースを調べて、スタック フレーム オブジェクトからの情報のみGetMethod()を使用します。CLR からのこの情報は、とが間違っていGetILOffset()ても、たまたま正しいものです。GetFileName()GetFileLineNumber()

  3. 次に、スタック フレームごとに、例外から取得したメソッド名と IL オフセットを使用して、生成されたデータベースを検索し、情報を持っている各スタック フレームの実際のファイル名と行番号を特定します。

  4. データベースで情報が見つからないフレームは、通常、コンパイル済みの .NET モジュールのスタック フレームであり、CLR から取得した情報は実際には正しいものです。これらのフレームでは、スタック フレームを直接使用GetFileName()します。GetFileLineNumber()

于 2014-01-14T16:43:25.130 に答える