Generieren von Quellcode aus .NET-Assemblys beim Debuggen

Wenn Sie eine .NET-Anwendung debuggen, möchten Sie möglicherweise Quellcode anzeigen, über den Sie nicht verfügen. Dies kann z. B. der Fall sein, um die Ausführung bei einer Ausnahme zu unterbrechen oder mithilfe der Aufrufliste zu einer Position im Quellcode zu navigieren.

Hinweis

  • Die Quellcodegenerierung (Dekompilierung) ist nur für .NET-Anwendungen verfügbar und basiert auf dem ILSpy-Open Source-Projekt.
  • Dekompilierung ist nur in Visual Studio 2019 16.5 und höher verfügbar.
  • Durch Anwenden des SuppressIldasmAttribute auf eine Assembly oder ein Modul wird die Kompilierung in Visual Studio verhindert. Obwohl das Attribut in .NET 6 und höher veraltet ist, berücksichtigt Visual Studio das Attribut.

Generieren von Quellcode

Wenn Sie debuggen und kein Quellcode verfügbar ist, wird in Visual Studio das Dokument Quelle nicht gefunden angezeigt. Wenn keine Symbole für die Assembly vorhanden sind, wird das Dokument Keine Symbole geladen angezeigt. Beide Dokumente verfügen über die Option Quellcode dekompilieren, mit der C#-Code für die aktuelle Position generiert wird. Der generierte C#-Code kann dann wie jeder andere Quellcode verwendet werden. Sie können den Code anzeigen, Variablen überprüfen, Haltepunkte festlegen usw.

Keine Symbole geladen

In der folgenden Abbildung wird die Meldung Keine Symbole geladen gezeigt.

Screenshot des Dokuments „Keine Symbole geladen“

Quelle nicht gefunden

In der folgenden Abbildung wird die Meldung Quelle nicht gefunden gezeigt.

Screenshot des Dokuments „Quelle nicht gefunden“

Automatische Dekompilierung von Code

Ab Visual Studio 2022, Version 17.7, unterstützt der Visual Studio Debugger die automatische Dekompilierung von externem .NET-Code. Sie können eine automatische Dekompilierung durchführen, wenn Sie externen Code schrittweise ausführen oder das Fenster „Aufrufliste“ verwenden.

Wenn Sie einen Code schrittweise ausführen, der extern implementiert wurde, wird der Debugger automatisch dekompiliert und zeigt den aktuellen Ausführungspunkt an. Wenn Sie externen Code schrittweise ausführen möchten, muss Nur eigenen Code deaktiviert sein.

Sie können im Fenster „Aufrufliste“ dekompilieren, ohne „Nur eigenen Code“ zu deaktivieren.

So dekompilieren Sie automatisch im Fenster „Aufrufliste“:

  1. Wählen Sie beim Debuggen im geöffneten Fenster „Aufrufliste“ die Option Externen Code anzeigen aus.

  2. Doppelklicken Sie im Fenster „Aufrufliste“ auf einen beliebigen Stapelrahmen. Der Debugger dekompiliert den Code und navigiert dann direkt zum aktuellen Ausführungspunkt.

    Screenshot des Fensters Aufrufliste mit externem Code.

    Der gesamte dekompilierte Code wird auch unter dem Knoten „Externe Quellen“ im Projektmappen-Explorer angezeigt und erleichtert das Durchsuchen der externen Dateien bei Bedarf.

    Screenshot des Knotens „Externe Quellen” mit dekompilierten Assemblys.

    Sie können den dekompilierten Code debuggen und Haltepunkte festlegen.

Um die automatische Dekompilierung von externem Code zu deaktivieren, wechseln Sie zu Extras > Optionen > Debuggen > Allgemein, und deaktivieren Sie bei Bedarf die Option Bei Bedarf automatisch in Quelle dekompilieren (nur verwaltet).

Generieren und Einbetten von Quellcode für eine Assembly

Zusätzlich zum Generieren von Quellcode für eine bestimmte Position können Sie den gesamten Quellcode für eine angegebene .NET-Assembly generieren. Wechseln Sie für diese Aufgabe zum Fenster Module, und wählen Sie dann im Kontextmenü einer .NET-Assembly den Befehl Quellcode in Symboldatei dekompilieren aus. Visual Studio generiert eine Symboldatei für die Assembly und bettet dann den Quellcode in die Symboldatei ein. In einem späteren Schritt können Sie den eingebetteten Quellcode extrahieren.

Screenshot des Kontextmenüs der Assembly im Fenster „Module“ mit dem Befehl „Quellcode dekompilieren“

Extrahieren und Anzeigen des eingebetteten Quellcodes

Sie können Quelldateien extrahieren, die in eine Symboldatei eingebettet sind. Verwenden Sie dazu den Befehl Extract Source Code (Quellcode extrahieren) im Kontextmenü des Fensters Module.

Screenshot des Kontextmenüs der Assembly im Fenster „Module“ mit dem Befehl zum Extrahieren des Quellcodes

Die extrahierten Quelldateien werden der Projektmappe als Sonstige Dateien hinzugefügt. Das Feature „Sonstige Dateien“ ist in Visual Studio standardmäßig deaktiviert. Sie können dieses Feature mit dem Kontrollkästchen Extras>Optionen>Umgebung>Dokumente>Sonstige Dateien im Projektmappen-Explorer anzeigen aktivieren. Wenn dieses Feature nicht aktiviert ist, können Sie den extrahierten Quellcode nicht öffnen.

Screenshot der Seite „Optionen“ unter „Extras“ mit aktivierter Option für sonstige Dateien

Extrahierte Quelldateien werden in den sonstigen Dateien im Projektmappen-Explorer angezeigt.

Screenshot des Projektmappen-Explorers mit sonstigen Dateien

Für .NET-Bibliotheken oder für NuGet-Pakete, die für SourceLink aktiviert sind, können Sie auch in den Quellcode einsteigen, Haltepunkte setzen und alle Funktionen des Debuggers nutzen. Weitere Informationen finden Sie unter Aktivieren von Debugging und Diagnose mit Source Link und unter Steigern der Produktivität zur Debugzeit mit Source Link.

Bekannte Einschränkungen

Unterbrechungsmodus erforderlich

Das Generieren von Quellcode durch Dekompilierung ist nur möglich, wenn sich der Debugger im Unterbrechungsmodus befindet und die Anwendung angehalten wurde. Beispielsweise wechselt Visual Studio in den Unterbrechungsmodus, wenn ein Haltepunkt oder eine Ausnahme erreicht wird. Mit dem Befehl Alle unterbrechen (Symbol „Alle unterbrechen) können Sie bei der nächsten Ausführung des Codes in Visual Studio den Unterbrechungsmodus aktivieren.

Einschränkungen bei der Dekompilierung

Das Erzeugen von Quellcode aus dem Zwischenformat (IL), das in .NET-Assemblys verwendet wird, ist mit einigen Einschränkungen verbunden. Der generierte Quellcode sieht nicht wie der ursprüngliche Quellcode aus. Die meisten Unterschiede bestehen an Stellen, an denen die Informationen im ursprünglichen Quellcode zur Laufzeit nicht benötigt werden. Beispielsweise werden Informationen wie Leerzeichen, Kommentare und die Namen lokaler Variablen zur Laufzeit nicht benötigt. Es wird empfohlen, den generierten Quellcode zum besseren Verständnis der Programmausführung und nicht als Ersatz für den ursprünglichen Quellcode zu verwenden.

Debuggen von optimierten oder Releaseassemblys

Beim Debuggen von Code, der aus einer mit Compileroptimierungen kompilierten Assembly dekompiliert wurde, können die folgenden Probleme auftreten:

  • Breakpoints werden möglicherweise nicht immer an die entsprechende Quellcodeposition gebunden.
  • Die schrittweise Ausführung endet möglicherweise nicht immer an der richtigen Position.
  • Lokale Variablen weisen möglicherweise keine korrekten Namen auf.
  • Einige Variablen können möglicherweise nicht ausgewertet werden.

Weitere Informationen finden Sie im GitHub-Problem: ICSharpCode.Decompiler integration into VS Debugger (Integration von ICSharpCode.Decompiler in den VS-Debugger, in englischer Sprache).

Zuverlässigkeit der Dekompilierung

Ein relativ kleiner Prozentsatz der Dekompilierungen führt möglicherweise zu einem Fehler. Die Ursache für dieses Verhalten ist ein Fehler aufgrund eines Sequenzpunkt-Nullverweises in ILSpy. Wir haben den Fehler abgeschwächt, indem diese Probleme abgefangen werden und die Dekompilierung ordnungsgemäß abgebrochen wird.

Weitere Informationen finden Sie im GitHub-Problem: ICSharpCode.Decompiler integration into VS Debugger (Integration von ICSharpCode.Decompiler in den VS-Debugger, in englischer Sprache).

Einschränkungen bei asynchronem Code

Die Ergebnisse der Dekompilierung von Modulen mit async/await-Codemustern sind möglicherweise unvollständig, oder die Dekompilierung schlägt vollständig fehl. Die ILSpy-Implementierung von async/await- und yield-Zustandsautomaten ist unvollständig.

Weitere Informationen finden Sie im GitHub-Problem: PDB Generator Status (PDB-Generator-Status, in englischer Sprache).

Nur eigenen Code

Mit der Einstellung Nur eigenen Code (Just My Code, JMC) können System-, Framework- und Bibliotheksaufrufe sowie andere nicht benutzerseitige Aufrufe in Visual Studio übersprungen werden. Während einer Debugsitzung wird im Fenster Module angezeigt, welche Codemodule vom Debugger als eigener Code (Benutzercode) behandelt werden.

Bei der Dekompilierung von optimierten Modulen oder Releasemodulen wird Nichtbenutzercode erzeugt. Wenn der Debugger beispielsweise die Ausführung von dekompiliertem Nichtbenutzercode unterbricht, wird das Fenster Keine Quelle angezeigt. Um „Nur eigenen Code“ zu deaktivieren, gehen Sie zu Extras>Optionen (oder Debuggen>Optionen) >Debugging>Allgemein, und deaktivieren Sie dann Nur meinen Code aktivieren.

Extrahierter Quellcode

Aus einer Assembly extrahierter Quellcode weist die folgenden Einschränkungen auf:

  • Der Name und der Speicherort der generierten Dateien sind nicht konfigurierbar.
  • Die Dateien sind temporär und werden von Visual Studio gelöscht.
  • Die Dateien werden in einem einzelnen Ordner abgelegt, und die ggf. vorhandene Ordnerhierarchie der ursprünglichen Quellcodedateien wird nicht verwendet.
  • Der Dateiname für jede Datei enthält einen Prüfsummenhash der Datei.

Es wird nur C#-Code generiert

Bei der Dekompilierung werden nur Quellcodedateien in C# generiert. Es gibt keine Option zum Generieren von Dateien in einer anderen Sprache.