デバッグ中に .NET アセンブリからソース コードを生成する
.NET アプリケーションをデバッグするときに、持っていないソース コードを表示したい場合があります。 たとえば、例外発生時にプログラムを中断したり、呼び出し履歴を利用してソース位置に移動したりします。
手記
- ソース コード生成 (逆コンパイル) は.NET アプリケーションでのみ使用でき、ILSpy プロジェクト オープン ソースに基づいています。
- 逆コンパイルは、Visual Studio 2019 16.5 以降でのみ使用できます。
- SuppressIldasmAttribute 属性をアセンブリまたはモジュールに適用すると、Visual Studio が逆コンパイルを試みなくなります。 この属性は .NET 6 以降では使用されていませんが、Visual Studio ではこの属性が使用されます。
ソース コードの生成
デバッグ中にソース コードが使用できない場合、Visual Studio には Source Not Found ドキュメントが表示されます。あるいは、アセンブリのシンボルがない場合には、No Symbols Loaded ドキュメントが表示されます。 どちらのドキュメントにも、現在の場所の C# コードを生成する 逆コンパイル ソース コード オプションがあります。 生成された C# コードは、他のソース コードと同様に使用できます。 コードの表示、変数の検査、ブレークポイントの設定などを行うことができます。
シンボルが読み込まれていない
次の図は、シンボルが読み込まれていないというメッセージを示しています。
のスクリーンショット
ソースが見つかりません
次の図は、Source Not Found メッセージを示しています。
のスクリーンショット
オートコンパイル コード
Visual Studio 2022 バージョン 17.7 以降、Visual Studio デバッガーでは、外部 .NET コードの自動コンパイルがサポートされています。 外部コードにステップ インするとき、または [呼び出し履歴] ウィンドウを使用する場合は、自動コンパイルできます。
外部で実装されたコードにステップ インすると、デバッガーによって自動的に逆コンパイルされ、現在の実行ポイントが表示されます。 外部コードにステップ インする場合は、[マイ コードのみ] を無効にします。
[マイ コードのみ] を無効にしなくても、[呼び出し履歴] ウィンドウから逆コンパイルできます。
[呼び出し履歴] ウィンドウからオートコンパイルするには:
[呼び出し履歴] ウィンドウを開いた状態でデバッグ中に、[外部コードの表示] を選択します。
[呼び出し履歴] ウィンドウで、任意のスタック フレームをダブルクリックします。 デバッガーはコードを逆コンパイルし、現在の実行ポイントに直接移動します。
逆コンパイルされたすべてのコードは、ソリューション エクスプローラーの [外部ソース] ノードにも表示されるため、必要に応じて外部ファイルを簡単に参照できます。
逆コンパイルされたコードをデバッグし、ブレークポイントを設定できます。
外部コードの自動逆コンパイルを無効にするには、[ツール] > [オプション] > [デバッグ] > [全般] に移動し、必要に応じてソースに自動的に逆コンパイルする (管理のみ) の選択を解除します。
アセンブリのソースを生成して埋め込む
特定の場所のソース コードを生成するだけでなく、特定の .NET アセンブリのすべてのソース コードを生成できます。 このタスクを実行するには、モジュール ウィンドウに移動し、.NET アセンブリのコンテキスト メニューから、逆コンパイル ソースからシンボル ファイルへの コマンドを選択します。 Visual Studio によってアセンブリのシンボル ファイルが生成され、ソースがシンボル ファイルに埋め込まれます。 後のステップで、埋め込まれたソース コードを抽出することができます。
埋め込みソース コードを抽出して表示する
シンボル ファイルに埋め込まれているソース ファイルは、[モジュール] ウィンドウのコンテキスト メニューの [ソース コードの抽出] コマンド 使用して抽出できます。
抽出されたソース ファイルは、ソリューションにその他の ファイルとして追加されます。 Visual Studio では、その他のファイル機能は既定でオフになっています。 この機能は、[ツール]>[オプション]>[環境>ドキュメント]>ソリューション エクスプローラーの [その他のファイルの表示] チェック ボックスから有効にすることができます。 この機能が有効になっていない場合、抽出されたソース コードを開くことはありません。
抽出されたソース ファイルは、ソリューション エクスプローラー のその他ファイルに表示されます。
SourceLink
.NET ライブラリの場合、または SourceLink で有効になっている NuGet パッケージの場合は、ソース コードにステップ インし、ブレークポイントを設定し、デバッガーのすべての機能を使用することもできます。 詳細については、「Source Link を使用してデバッグと診断を有効にする と、SourceLink を使用したデバッグ時の生産性の向上を参照してください。
既知の制限事項
中断モードが必要
逆コンパイルを使用してソース コードを生成できるのは、デバッガーが中断モードで、アプリケーションが一時停止している場合のみです。 たとえば、ブレークポイントまたは例外にヒットすると、Visual Studio は中断モードに入ります。 [すべて中断] コマンド([すべて中断] アイコン)を使用すると、次回コードを実行する際に Visual Studio を簡単に中断することができます。
逆コンパイルの制限事項
.NET アセンブリで使用される中間形式 (IL) からソース コードを生成する場合、固有の制限事項がいくつかあります。 そのため、生成されたソース コードは元のソース コードのようには見えません。 異なっているのは、ほとんどが、元のソース コードの情報が実行時に必要のない箇所です。 たとえば、空白、コメント、ローカル変数の名前などの情報は、実行時には必要ありません。 生成されたソースを使用して、元のソース コードの代わりにではなく、プログラムの実行方法を理解することをお勧めします。
最適化されたアセンブリまたはリリース アセンブリをデバッグする
コンパイラの最適化を使用してコンパイルされたアセンブリから逆コンパイルされたコードをデバッグすると、次の問題が発生する可能性があります。
- ブレークポイントは、必ずしも一致するソースの場所にバインドされるとは限りません。
- ステップ実行では、正しい場所に常にステップ実行するとは限りません。
- ローカル変数の名前が正確でない場合があります。
- 一部の変数は評価に使用できない場合があります。
詳細については、GitHub の問題を参照してください。ICSharpCode.Decompiler を VS Debuggerに統合します。
逆コンパイルの信頼性
逆コンパイルの試行の割合が比較的小さいと、エラーが発生する可能性があります。 この動作は、ILSpy のシーケンス ポイントの null 参照エラーが原因です。 これらの問題をキャッチし、逆コンパイルの試行を適切に失敗させることで、エラーを軽減しました。
詳細については、GitHub の問題を参照してください。ICSharpCode.Decompiler を VS Debuggerに統合します。
非同期コードに関する制限事項
非同期/待機コード パターンを使用してモジュールを逆コンパイルした結果は、不完全であるか、完全に失敗する可能性があります。 async/await および yield ステート マシンの ILSpy 実装は、部分的にのみ実装されます。
詳細については、GitHub の問題「PDB ジェネレーターの状態」を参照してください。
マイ コードのみ
Just My Code (JMC) 設定を使用すると、Visual Studio でシステム、フレームワーク、ライブラリ、およびその他の非ユーザー呼び出しをステップ オーバーできます。 デバッグ セッション中に、[モジュール] ウィンドウには、デバッガーがマイ コード (ユーザー コード) として扱うコード モジュールが表示されます。
最適化されたモジュールまたはリリース モジュールを逆コンパイルすると、非ユーザー コードが生成されます。 たとえば、逆コンパイルされた非ユーザー コードでデバッガーが中断された場合は、[ソース なし] ウィンドウが表示されます。 マイ コードのみを無効にするには、[ツール>オプション] (デバッグ>オプション) に移動し、>[デバッグ]>[全般]を選択して、[マイ コードのみを有効にする]の選択を解除します。
抽出されたソース
アセンブリから抽出されるソース コードには、次の制限があります。
- 生成されたファイルの名前と場所は構成できません。
- ファイルは一時的であり、Visual Studio によって削除されます。
- ファイルは 1 つのフォルダーに配置され、元のソースが使用していたフォルダー階層は使用されません。
- 各ファイルのファイル名には、ファイルのチェックサム ハッシュが含まれています。
生成されたコードは C# のみ
逆コンパイルでは、C# でソース コード ファイルのみが生成されます。 他の言語でファイルを生成するオプションはありません。