Übung: Debuggen mit Visual Studio Code

Abgeschlossen

Jetzt ist es Zeit, Ihr neu erworbenes Wissen über das Debuggen in die Praxis umzusetzen. Es ist Ihr erster Tag an Ihrer neuen Stelle und an der Zeit, Ihre Fähigkeiten zum Debuggen von .NET einzubringen, indem Sie einen Fehler im Vorzeigeprodukt des Unternehmens, einem Fibonacci-Rechner, beheben.

Erstellen eines .NET-Beispielprojekts für das Debuggen

Zum Einrichten von Visual Studio Code für das Debuggen von .NET benötigen wir zuerst ein .NET-Projekt. Visual Studio Code enthält ein integriertes Terminal, mit dem das Erstellen eines neuen Projekts ganz einfach ist.

  1. Klicken Sie in Visual Studio Code auf Datei>Ordner öffnen.

  2. Erstellen Sie am Speicherort Ihrer Wahl einen neuen Ordner namens DotNetDebugging. Wählen Sie dann Ordner auswählen aus.

  3. Öffnen Sie das integrierte Terminal über Visual Studio Code, indem Sie im Hauptmenü auf Ansicht>Terminal klicken.

  4. Kopieren Sie den folgenden Befehl, und fügen Sie ihn in das Terminalfenster ein:

    dotnet new console
    

    Dieser Befehl erstellt in Ihrem Ordner die Datei Program.cs mit einem einfachen, vorgefertigten „Hallo Welt“-Programm. Eine C#-Projektdatei namens DotNetDebugging.csproj wird ebenfalls erstellt.

  5. Kopieren Sie den folgenden Befehl, und fügen Sie ihn in das Terminalfenster ein, um das „Hallo Welt“-Programm auszuführen.

    dotnet run
    

    Im Terminalfenster wird „Hello World!“ (Hallo Welt!) als Ausgabe angezeigt.

Einrichten von Visual Studio Code für das Debuggen von .NET

  1. Öffnen Sie Program.cs, indem Sie die Datei auswählen.

  2. Wenn Sie zum ersten Mal eine C#-Datei in Visual Studio Code öffnen, werden Sie aufgefordert, die empfohlenen Erweiterungen für C# zu installieren. Klicken Sie in dieser Eingabeaufforderung auf die Schaltfläche Installieren.

    Screenshot der Visual Studio Code-Eingabeaufforderung zur Installation der C#-Erweiterung.

  3. Visual Studio Code installiert die Erweiterung für C# und zeigt eine weitere Eingabeaufforderung an, um die zum Kompilieren und Debuggen des Projekts erforderlichen Ressourcen hinzuzufügen. Klicken Sie auf die Schaltfläche Ja.

    Screenshot der Visual Studio Code-Aufforderung zum Hinzufügen erforderlicher Ressourcen zum Erstellen und Debuggen des .NET-Projekts.

  4. Sie können die Registerkarte Erweiterung: C# schließen, um sich auf den Code zu konzentrieren, den wir debuggen.

Hinzufügen der Programmlogik für die Fibonacci-Folge

Unser aktuelles Projekt gibt eine Hallo Welt-Meldung in der Konsole aus, die uns nicht viel zum Debuggen anbietet. Stattdessen verwenden Sie ein kurzes .NET-Programm, um die n-te Zahl der Fibonacci-Folge zu berechnen.

Die Fibonacci-Folge ist eine Reihe von Zahlen, die mit den Ziffern 0 und 1 beginnt und in der jede folgende Zahl die Summe der beiden vorherigen Zahlen ist. Die Folge setzt sich so fort:

0, 1, 1, 2, 3, 5, 8, 13, 21...
  1. Öffnen Sie Program.cs, indem Sie die Datei auswählen.

  2. Ersetzen Sie den Inhalt von Program.cs durch den folgenden Code:

    int result = Fibonacci(5);
    Console.WriteLine(result);
    
    static int Fibonacci(int n)
    {
        int n1 = 0;
        int n2 = 1;
        int sum;
    
        for (int i = 2; i < n; i++)
        {
            sum = n1 + n2;
            n1 = n2;
            n2 = sum;
        }
    
        return n == 0 ? n1 : n2;
    }
    

    Hinweis

    Dieser Code enthält einen Fehler, den wir später in diesem Modul debuggen werden. Sie sollten diesen Code nicht in unternehmenskritischen Fibonacci-Anwendungen verwenden, bis wir den Fehler behoben haben.

  3. Speichern Sie die Datei. Unter Windows und Linux drücken Sie dafür die Tastenkombination STRG+S. Auf einem Mac drücken Sie CMD+S.

  4. Sehen wir uns nun an, wie der aktualisierte Code funktioniert, bevor wir ihn debuggen. Führen Sie das Programm aus, indem Sie im Terminal folgenden Code eingeben:

    dotnet run
    

    Terminalfenster mit modifizierter Programmausgabe.

  5. Das Ergebnis wird in der Terminalausgabe angezeigt: 3. Wenn Sie dieses Diagramm der Fibonacci-Folge konsultieren, in dem die auf der Null basierende Sequenzposition für jeden Wert in Klammern angezeigt wird, werden Sie sehen, dass das Ergebnis 5 hätte sein müssen. Es ist an der Zeit, sich mit dem Debugger vertraut zu machen und dieses Programm zu beheben.

    0 (0), 1 (1), 1 (2), 2 (3), 3 (4), 5 (5), 8 (6), 13 (7), 21 (8)...
    

Analysieren der Probleme

  1. Starten Sie das Programm, indem Sie auf der linken Seite die Registerkarte Ausführen und Debuggen und dann die Schaltfläche Debuggen starten auswählen. Möglicherweise müssen Sie zuerst die Schaltfläche Ausführen und Debuggen und dann die Program.cs Datei auswählen.

    Screenshot: Schaltfläche „Debugging starten“ in Visual Studio Code

    Die Programmausführung sollte schnell abgeschlossen sein, denn Sie haben noch keine Haltepunkte hinzugefügt.

  2. Wenn die Debugging-Konsole nicht angezeigt wird, drücken Sie unter Windows und Linux die Tastenkombination STRG+UMSCHALT+Y oder BEFEHLSTASTE+UMSCHALT+Y unter Mac. Sie sollten mehrere Zeilen mit Diagnoseinformationen sehen, gefolgt von diesen Zeilen am Ende:

    ...
    Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.0\System.Threading.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
    Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.0\System.Text.Encoding.Extensions.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
    3
    The program '[88820] DotNetDebugging.dll' has exited with code 0 (0x0).
    

Die Zeilen oben zeigen Ihnen, dass in den Standardeinstellungen für das Debuggen die Option „Nur eigenen Code“ aktiviert ist. Dies bedeutet Folgendes: Wenn Sie diesen Modus beibehalten, debuggt der Debugger nur Ihren Code und führt nicht den Quellcode für .NET schrittweise aus. Diese Option ermöglicht es Ihnen, sich voll und ganz auf das Debuggen Ihres Codes zu konzentrieren.

Am Ende der Ausgabe der Debugging-Konsole sehen Sie, dass das Programm die Ziffer 3 in der Konsole ausgibt und dann mit Code 0 beendet wird. Normalerweise gibt der Exitcode 0 an, dass das Programm ausgeführt und ohne Absturz beendet wurde. Es gibt jedoch einen Unterschied zwischen Absturz und Rückgabe des korrekten Werts. In diesem Fall haben wir das Programm aufgefordert, den fünften Wert der Fibonacci-Folge zu berechnen:

0 (0), 1 (1), 1 (2), 2 (3), 3 (4), 5 (5), 8 (6), 13 (7), 21 (8)...

Der fünfte Wert in dieser Liste ist 5, unser Programm hat aber 3 zurückgegeben. Untersuchen und korrigieren wir den Fehler mit dem Debugger.

Verwenden von Haltepunkten und Ausführung in Einzelschritten

  1. Fügen Sie einen Haltepunkt hinzu, indem Sie in Zeile 1 im linken Randbereich auf int result = Fibonacci(5); klicken.

    Screenshot: Position des Haltepunkts im Code

  2. Starten Sie das Debuggen erneut. Das Programm beginnt mit der Ausführung. Aufgrund des von Ihnen festgelegten Haltepunkts wird die Ausführung in Zeile 1 unterbrochen (angehalten). Verwenden Sie die Steuerelemente des Debuggers, um in die Fibonacci()-Funktion schrittweise auszuführen.

    Screenshot: Schaltfläche „Einzelschritt“

Überprüfen des Variablenzustands

Nehmen Sie sich nun etwas Zeit, um im Panel Variablen die verschiedenen Variablenwerte zu überprüfen.

Screenshot: Panel „Variablen“

  • Welcher Wert wird für den Parameter n angezeigt?
  • Wie lauten die Werte für die lokalen Variablen n1, n2 und sum am Anfang der Funktionsausführung?
  1. Als Nächstes wechseln wir mit dem Steuerelement Prozedurschritt des Debuggers in die for-Schleife.

    Screenshot: Schaltfläche „Prozedurschritt“

  2. Fahren Sie fort, bis Sie auf die erste Zeile innerhalb der for-Schleife treffen, die so lautet:

    sum = n1 + n2;
    

Hinweis

Möglicherweise haben Sie bemerkt, dass für die Navigation in der for(...) {}-Zeile mehrere Einzelschrittbefehle erforderlich sind. Der Grund hierfür ist, dass diese Zeile mehrere Anweisungen enthält. Wenn Sie einen Schritt ausführen, wird mit der nächsten Anweisung im Code fortgefahren. Üblicherweise gibt es eine Anweisung pro Zeile. Sollte dies nicht der Fall sein, müssen Sie mehrere Schritte ausführen, um zur nächsten Zeile zu wechseln.

Überlegungen zum Code

Ein wichtiger Teil des Debuggens besteht darin, anzuhalten und Vermutungen darüber anzustellen, was Ihrer Meinung nach Teile des Codes (sowohl Funktionen als auch Blöcke, wie z. B. Schleifen) zu erreichen versuchen. Es macht nichts, wenn Sie sich nicht sicher sind, denn das ist Teil des Debugprozesses. Doch wenn Sie sich aktiv am Debugprozess beteiligen, können Sie Fehler viel schneller finden.

Bevor wir fortfahren, rufen Sie sich in Erinnerung: Die Fibonacci-Folge ist eine Reihe von Zahlen, die mit den Ziffern 0 und 1 beginnt und in der jede folgende Zahl die Summe der beiden vorherigen Zahlen ist.

Dies bedeutet Folgendes:

Fibonacci(0) = 0
Fibonacci(1) = 1
Fibonacci(2) = 1 (0 + 1)
Fibonacci(3) = 2 (1 + 1)
Fibonacci(4) = 3 (1 + 2)
Fibonacci(5) = 5 (2 + 3)

Wenn Sie diese Definition verstehen und sich diese for-Schleife ansehen, können wir Folgendes ableiten:

  1. Die Schleife zählt von 2 bis n (die von uns gesuchte Zahl in der Fibonacci-Folge).
  2. Wenn n kleiner als 2 ist, wird die Schleife nie ausgeführt. Die return-Anweisung am Ende der Funktion gibt 0 zurück, wenn n gleich 0 ist, und 1, wenn n gleich 1 oder 2 ist. Dies sind definitionsgemäß der nullte, der erste und der zweite Wert in der Fibonacci-Folge.
  3. Der interessantere Fall ist, wenn n größer als 2 ist. In diesen Fällen wird der aktuelle Wert als Summe der beiden vorherigen Werte definiert. Daher sind bei dieser Schleife n1 und n2 die beiden vorherigen Werte, und sum ist der Wert für die aktuelle Iteration. Aus diesem Grund werden jedes Mal, wenn wir die Summe der beiden vorherigen Werte ermitteln und auf sum festlegen, unsere Werte n1 und n2 aktualisiert.

Genug der grauen Theorie – wenden wir uns lieber wieder dem Debugger zu. Es lohnt sich aber, sich mit dem Code zu beschäftigen, um herauszufinden, ob er das erwartete Ergebnis erzielt, und ihn ggf. korrigieren zu können.

Suchen des Fehlers mithilfe von Haltepunkten

Es kann zwar hilfreich sein, Ihren Code schrittweise zu durchlaufen, aber auch mühsam, insbesondere dann, wenn Sie mit Schleifen oder anderem Code arbeiten, der wiederholt aufgerufen wird. Anstatt die Schleife mehrmals schrittweise auszuführen, können wir in der ersten Zeile der Schleife einen neuen Haltepunkt setzen.

Dabei ist es wichtig, beim Setzen der Haltepunkte strategisch vorzugehen. Wir interessieren uns besonders für den Wert von sum, da er den aktuellen maximalen Fibonacci-Wert darstellt. Deshalb sollten wir unseren Haltepunkt in der Zeile setzen, nachdem sum festgelegt wurde.

  1. Fügen Sie in Zeile 13 einen zweiten Haltepunkt hinzu.

    Screenshot, der zeigt, wie ein zweiter Haltepunkt gesetzt wird.

    Hinweis

    Wenn Sie feststellen, dass Sie Ihren Code weiter ausführen und dann ein oder zwei Zeilen weitergehen, können Sie Ihre Haltepunkte leicht in effizientere Zeilen ändern.

  2. Nachdem wir nun einen geeigneten Haltepunkt in der Schleife gesetzt haben, verwenden Sie das Steuerelement Weiter des Debuggers, um fortzufahren, bis der Haltepunkt erreicht ist. Bei einem Blick auf unsere lokalen Variablen sehen wir folgende Zeilen:

    n [int]: 5
    n1 [int]: 0
    n2 [int]: 1
    sum [int]: 1
    i [int]: 2
    

    All diese Zeilen sehen richtig aus. Beim ersten Durchlaufen der Schleife ist sum der vorherigen beiden Werte 1. Anstatt nun Zeile für Zeile schrittweise voranzugehen, können wir unsere Haltepunkte nutzen, um zum nächsten Schleifendurchlauf zu springen.

  3. Klicken Sie auf Weiter, um den Programmfluss fortzusetzen, bis der nächste Haltepunkt erreicht ist – dies ist beim nächsten Durchlauf durch die Schleife der Fall.

    Hinweis

    Machen Sie sich keine Gedanken über das Überspringen des Fehlers, wenn Sie auf Weiter klicken. Sie müssen damit rechnen, dass Sie den Code häufig mehrmals debuggen müssen, um das Problem zu finden. Dennoch geht es oft schneller, den Debuggingprozess mehrmals auszuführen, als den Code in Einzelschritten zu durchlaufen.

    Dieses Mal werden die folgenden Werte angezeigt:

    n [int]: 5
    n1 [int]: 1
    n2 [int]: 1
    sum [int]: 2
    i [int]: 3
    

    Lassen Sie uns überlegen: Sind diese Werte immer noch sinnvoll? Erst einmal schein es so. Für die dritte Fibonacci-Zahl erwarten wir, dass unsere sum gleich 2 ist, was ja auch stimmt.

  4. OK. Klicken wir also auf Weiter, um die Schleife erneut zu durchlaufen.

    n [int]: 5
    n1 [int]: 1
    n2 [int]: 2
    sum [int]: 3
    i [int]: 4
    

    Wiederum sieht alles gut aus. Der vierte Wert in der Reihe sollte die 3 sein.

  5. An diesem Punkt werden Sie sich vielleicht fragen: „War der Code die ganze Zeit richtig? Habe ich mir den Fehler nur eingebildet?“ Lassen Sie uns nun die Schleife ein letztes Mal durchlaufen. Klicken wir ein weiteres Mal auf Weiter.

    Moment mal! Die Ausführung des Programms wurde beendet, und es wurde 3 ausgegeben! Das ist nicht korrekt.

    Aber keine Sorge. Wir sind nicht gescheitert, sondern haben etwas gelernt. Wir wissen jetzt, dass der Code die Schleife einwandfrei durchläuft, bis i gleich 4 ist. Aber dann wird seine Ausführung beendet, ehe der endgültige Wert berechnet wird. Ich glaube, ich weiß langsam, wo der Fehler liegt. Sie auch?

  6. Legen Sie einen weiteren Haltepunkt in Zeile 17 fest, die wie folgt lautet:

    return n == 0 ? n1 : n2;
    

    Mit diesem Haltepunkt können wir den Programmzustand überprüfen, bevor die Funktion beendet wird. Unsere bisherigen Haltepunkten in den Zeilen 1 und 13 enthalten keine neuen Informationen mehr für uns, daher löschen wir sie.

  7. Entfernen Sie die vorherigen Haltepunkte aus den Zeilen 1 und 13. Klicken Sie dazu im Randbereich neben den Zeilennummern auf sie, oder deaktivieren Sie im Bereich „Haltepunkte“ links unten die Kontrollkästchen Haltepunkt für die Zeilen 1 und 13.

    Screenshot mit den im Bereich „Haltepunkte“ aufgeführten Haltepunkten.

    Da wir nun viel besser verstehen, was vor sich geht, und einen Haltepunkt gesetzt haben, um unser Programm bei fehlerhaftem Verhalten zu erwischen, sollten wir in der Lage sein, diesen Fehler abzufangen!

  8. Starten Sie den Debugger ein letztes Mal.

    n [int]: 5
    n1 [int]: 2
    n2 [int]: 3
    sum [int]: 3
    

    Nun, das stimmt nicht. Wir haben ausdrücklich „Fibonacci(5)“ angefordert, bekommen aber „Fibonacci(4)“. Diese Funktion gibt n2 zurück, und jede Schleifeniteration berechnet den Wert von sum und legt n2 auf den Wert von sum fest.

    Basierend auf diesen Informationen und dem vorherigen Debuglauf erkennen Sie, dass die Schleife beendet wurde, als i 4 und nicht 5 war.

    Sehen wir uns nun die erste Zeile der for-Schleife etwas genauer an.

    for (int i = 2; i < n; i++)
    

    Augenblick mal! Das bedeutet, dass die for-Schleife beendet wird, sobald festgestellt wird, dass i nicht mehr kleiner ist als n. Das wiederum heißt, dass der Schleifencode im Fall von i gleich n nicht ausgeführt wird. Es scheint, als wollten wir stattdessen die Ausführung bis i <= n durchführen:

    for (int i = 2; i <= n; i++)
    

    Mit dieser Änderung sollte das aktualisierte Programm wie im folgenden Beispiel aussehen:

    int result = Fibonacci(5);
    Console.WriteLine(result);
    
    static int Fibonacci(int n)
    {
        int n1 = 0;
        int n2 = 1;
        int sum;
    
        for (int i = 2; i <= n; i++)
        {
            sum = n1 + n2;
            n1 = n2;
            n2 = sum;
        }
    
        return n == 0 ? n1 : n2;
    }
    
  9. Beenden Sie die Debugsitzung, falls noch nicht geschehen.

  10. Nehmen Sie als Nächstes die oben genannte Änderung in Zeile 10 vor, und belassen Sie den Haltepunkt in Zeile 17.

  11. Starten Sie den Debugger neu. Wenn wir dieses Mal den Haltepunkt in Zeile 17 erreichen, sehen wir die folgenden Werte:

    n [int]: 5
    n1 [int]: 3
    n2 [int]: 5
    sum [int]: 5
    

    Komm schon! Das sieht vielversprechend aus! Gute Arbeit, Sie haben Fibonacci, Inc. den Tag gerettet!

  12. Klicken Sie auf Weiter, nur um sicherzustellen, dass das Programm den richtigen Wert zurückgibt.

    5
    The program '[105260] DotNetDebugging.dll' has exited with code 0 (0x0).
    

    Und das gibt die korrekte Ausgabe zurück.

Geschafft! Sie haben den .NET-Debugger von Visual Studio Code erfolgreich zum Debuggen von nicht selbst geschriebenem Code verwendet.

In der nächsten Lerneinheit erfahren Sie, wie Sie von Ihnen selbst geschriebenen Code mithilfe der in .NET integrierten Features zur Protokollierung und Ablaufverfolgung einfacher debuggen können.