偵錯時從 .NET 組件產生原始程式碼

偵錯 .NET 應用程式時,您可能會發現您想要檢視您沒有的原始程式碼。 例如,中斷例外狀況或使用呼叫堆疊瀏覽至來源位置。

注意

  • 原始程式碼產生 (反向組譯) 僅適用於 .NET 應用程式,且是以開放原始碼 ILSpy 專案為基礎。
  • 反向組譯僅適用於 Visual Studio 2019 16.5 和更新版本。
  • SuppressIldasmAttribute 屬性套用至組件或模組,可防止 Visual Studio 嘗試反向組譯。 雖然 .NET 6 和更新版本中的屬性已淘汰,但 Visual Studio 仍會接受屬性。

產生原始程式碼

當您在進行偵錯且沒有原始程式碼可用時,Visual Studio 會顯示 [找不到來源] 文件,或如果您沒有組件的符號,則會顯示 [未載入符號] 文件。 這兩份文件都有「反向組譯原始程式碼」選項,可產生目前位置的 C# 程式碼。 然後,您可以如同任何其他原始程式碼一樣使用產生的 C# 程式碼。 您可以檢視程式碼、檢查變數、設定中斷點等等。

未載入符號

下圖顯示 [未載入符號] 訊息。

Screenshot of no symbol loaded document

找不到原始碼

下圖顯示 [找不到來源] 訊息。

Screenshot of source not found document

自動反編譯程式碼

從 Visual Studio 2022 17.7 版開始,Visual Studio 偵錯工具支援外部 .NET 程式碼的自動反編譯。 當您進入外部程式碼或使用 Call Stack 視窗時,可以自動反編譯。

如果您逐步執行已在外部實作的程式碼,偵錯工具會自動反編譯程式碼並顯示目前的執行點。 如果您要進入外部程式碼,必須停用 Just My Code。

您可以從 Call Stack 視窗輕鬆取消反編譯,而不停用 Just My Code。

若要從 Call Stack 視窗自動取消反編譯,請執行下列動作:

  1. 在偵錯時開啟 Call Stack 視窗,選取 Show External Code。

  2. 在 Call Stack 視窗中,按兩下任何堆疊框架。 偵錯工具會解程式設計式碼,然後直接導覽至目前的執行點。

    Screenshot of Call Stack window showing external code.

    所有解編程式代碼也會顯示在方案總管的 [外部來源] 節點下,以便在需要時更輕鬆地瀏覽外部檔案。

    Screenshot of External Sources node showing decompiled assemblies.

    您可以偵錯已解譯的程式碼並設定中斷點。

若要停用外部程式碼的自動反編譯,請移至 >Tools Options >Debugging General >並取消選取必要時 Automatically decompile (僅限管理)。

產生和內嵌組件的來源

除了針對特定位置產生原始程式碼之外,您還可以為指定的 .NET 組件產生所有原始程式碼。 若要進行這個工作,請移至 [模組] 視窗,然後從 .NET 組件的捷徑功能表中,選取 [反向組譯來源至符號檔案] 命令。 Visual Studio 會產生組件的符號檔,然後將來源內嵌至符號檔。 在稍後的步驟中,您可以擷取內嵌的原始程式碼。

Screenshot of assembly context menu in modules window with decompile source command.

擷取並檢視內嵌的原始程式碼

您可以使用 [模組] 視窗操作功能表中的 [擷取原始程式碼] 命令,擷取內嵌在符號檔中的原始程式檔。

Screenshot of assembly context menu in modules window with extract sources command.

擷取的來源檔案會新增至解決方案做為其他檔案。 Visual Studio 預設會關閉其他檔案功能。 您可以從 [工具]>[選項]>[環境]>[文件]>[在方案總管中顯示其他檔案] 核取方塊啟用此功能。 如果未啟用此功能,您會無法開啟擷取的原始程式碼。

Screenshot of tools option page with miscellaneous files option enabled.

擷取的來源檔案會出現在 [方案總管] 的其他檔案中。

Screenshot of solution explorer with miscellaneous files.

對於針對 SourceLink 啟用的 .NET 程式庫或 NuGet 套件,您也可以逐步執行原始程式碼、設定中斷點,以及使用所有偵錯工具的功能。 如需詳細資訊,請參閱使用 Source Link 啟用偵錯和診斷,以及使用 Source Link 來改善偵錯時間的生產力

已知的限制

需要中斷模式

只有在偵錯工具處於中斷模式且應用程式暫停時,才能使用反向組譯產生原始程式碼。 例如,當 Visual Studio 叫用中斷點或例外狀況時,就會進入中斷模式。 您可以使用 [全部中斷] 命令 (Break all icon),以在下次執行程式碼時輕鬆觸發 Visual Studio 中斷。

反向組譯限制

從 .NET 組件中使用的中繼格式 (IL) 產生原始程式碼會有一些固有的限制。 因此,產生的原始程式碼看起來不像原始程式碼。 大部分的差異在於執行階段不需要資訊在原始程式碼中的位置。 例如,執行階段不需要空白字元、註解和區域變數名稱等資訊。 建議您使用產生的來源來了解程式的執行方式,而不是原始程式碼的取代項目。

對最佳化或發行組件進行偵錯

對從使用編譯器最佳化進行編譯的組件反向組譯的程式碼進行偵錯時,您可能會遇到下列問題:

  • 中斷點不一定會繫結至相符的來源位置。
  • 逐步執行不一定會逐步執行正確的位置。
  • 區域變數可能沒有正確的名稱。
  • 某些變數可能無法用於評估。

您可以在 GitHub 問題中找到更多詳細資料:ICSharpCode.Decompiler 與 VS 偵錯工具整合

反向組譯可靠性

相對小的反向組譯嘗試百分比可導致失敗。 這是因為 ILSpy 中的序列點 Null 參考錯誤。 我們已擷取這些問題,並正常地讓反向組譯嘗試失敗來減輕失敗。

您可以在 GitHub 問題中找到更多詳細資料:ICSharpCode.Decompiler 與 VS 偵錯工具整合

非同步程式碼的限制

使用 async/await 程式碼模式進行反向組譯模組的結果可以不完整或完全失敗。 async/await 和 yield 狀態機器的 ILSpy 實作只會部分實作。

如需詳細資訊,請參閱 GitHub 問題:PDB 產生器狀態

Just My Code

Just My Code (JMC) 設定可讓 Visual Studio 逐步執行系統、架構、程式庫和其他非使用者呼叫。 在偵錯工作階段期間,[模組] 視窗會顯示偵錯工具將哪些程式碼模組視為 [我的程式碼] (使用者程式碼)。

最佳化或發行模組的反向組譯會產生非使用者程式碼。 例如,如果偵錯工具在反向組譯的非使用者程式碼中中斷,則 [沒有來源] 視窗隨即出現。 若要停用 Just My Code,請瀏覽至 [工具]>[選項] (或 [偵錯]>[選項]) >[偵錯]>[一般] 下,然後取消選取 [啟用 Just My Code]

擷取的來源

從組件擷取的原始程式碼具有下列限制:

  • 無法設定所產生檔案的名稱和位置。
  • 這些檔案是暫時的,且已被 Visual Studio 刪除。
  • 這些檔案會放在單一資料夾中,且未使用原始來源的任何資料夾階層。
  • 每個檔案的檔案名都包含檔案的總和檢查碼雜湊。

產生的程式碼僅限 C#

反向組譯只會在 C# 中產生原始程式碼檔案。 沒有任何選項可以產生任何其他語言的檔案。