Übung: Debuggen mit Visual Studio

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 Sie möchten 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 für das Debuggen von .NET benötigen wir zuerst ein .NET-Projekt. Visual Studio bietet zahlreiche grundlegende Vorlagen, mit denen sich ganz einfach neue Projekte erstellen lassen.

  1. Klicken Sie in Visual Studio auf Datei>Neu>Projekt.

  2. Wählen Sie im Dialogfeld Neues Projekt erstellen die Option Konsolen-App und anschließend Weiter aus.

  3. Nennen Sie das Projekt DotNetDebugging, und wählen Sie den gewünschten Speicherort aus. Lassen Sie die restlichen Werte unverändert, und wählen Sie Weiter aus.

  4. Wählen Sie auf dem letzten Bildschirm auf Erstellen aus.

Daraufhin erstellt Visual Studio das Konsolenprojekt unter Verwendung der ausgewählten Vorlage. Warten Sie, bis das Projekt geladen wurde, und wählen Sie dann Program.cs aus, um es zu öffnen.

Füge die Programmlogik für die Fibonacci-Folge hinzu

Unser aktuelles Projekt gibt eine Hallo Welt-Meldung in der Konsole aus, die uns nicht viel zum Debuggen anbietet. Stattdessen verwenden wir 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...

Der folgende Beispielcode enthält einen Fehler. Daher verwenden wir die Debugtools von Visual Studio, um das Problem zu diagnostizieren und zu beheben.

  1. Ersetzen Sie den Inhalt von Program.cs durch den folgenden Code:
int result = Fibonacci(5);
Console.WriteLine(result);

static int Fibonacci(int n)
{
    Console.WriteLine("The output is: ");
    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.

  1. Speichern Sie die Datei durch Drücken von STRG+S (für Windows und Linux). Auf einem Mac drücken Sie CMD+S.

  2. Sehen wir uns nun an, wie der aktualisierte Code funktioniert, bevor wir ihn debuggen. Führen Sie das Programm aus, indem Sie in der Befehlsleiste von Visual Studio die grüne Startschaltfläche drücken.

  3. Am Ende der Ausgabe der Debugging-Konsole können Sie erkennen, 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.

Terminalfenster mit modifizierter Programmausgabe.

In diesem Fall haben wir das Programm aufgefordert, den fünften Wert der Fibonacci-Folge zu berechnen:

0, 1, 1, 2, 3, 5, 8, 13, 21...

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.

  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 schrittweise in die Fibonacci()-Funktion einzusteigen.

    Screenshot: Schaltfläche „Schrittweise ausführen“

Überprüfen des Variablenzustands

Nehmen Sie sich nun etwas Zeit, und überprüfen Sie im Fenster Lokale Variablen die Werte der verschiedenen Variablen.

Screenshot des Panels „Lokale 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 „Schritt über“

  2. Fahren Sie fort, bis Sie die erste Zeile innerhalb der for-Schleife erreichen. Es ist die Zeile, die folgendermaßen lautet:

    sum = n1 + n2;
    

Hinweis

Möglicherweise fällt Ihnen auf, 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, gehen Sie zur nächsten Anweisung in Ihrem Code über. Ü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. Diese Werte 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. Aufgrund dieser Logik werden jedes Mal, wenn wir die Summe der beiden vorherigen Werte ermitteln und auf sum festlegen, unsere Werte n1 und n2 aktualisiert.

Okay, wir müssen es nicht weiter überdenken. Wir können uns ein wenig auf unseren Debugger verlassen. Es lohnt sich jedoch, über den Code nachzudenken, um zu sehen, ob er das tut, was wir erwarten, und besser informiert zu sein, wenn er es nicht tut.

Suchen des Fehlers mithilfe von Haltepunkten

Den Code schrittweise zu durchlaufen, kann hilfreich sein, ist aber auch sehr mühsam. Dies gilt besonders dann, wenn Sie mit Schleifen oder anderen wiederholt aufgerufen Codeteilen arbeiten. Anstatt die Schleife mehrmals schrittweise auszuführen, können wir in der ersten Zeile der Schleife einen neuen Haltepunkt setzen.

Beim Platzieren der Haltepunkte ist es wichtig, strategisch vorzugehen. Wir interessieren uns besonders für den Wert von sum, da er den aktuellen maximalen Fibonacci-Wert darstellt. Lassen Sie und deshalb unseren Haltepunkt in der Zeile setzen, nachdemsum festgelegt wurde.

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

    Screenshot, der zeigt, wie ein zweiter Haltepunkt festgelegt 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, wählen Sie das Steuerelement Weiter des Debuggers aus, 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 möglicherweise 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
    

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

  4. Wählen Sie Weiter aus, um die Schleife erneut zu durchlaufen.

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

    Das Ergebnis ist korrekt. Der vierte Wert in der Reihe wird voraussichtlich 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.

    Die Ausführung des Programms wurde beendet, und die Ausgabe lautet 3! Unser Ergebnis ist falsch.

    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. Wir haben den Ort des Fehlers eingegrenzt.

  6. Platzieren Sie einen weiteren Haltepunkt in Zeile 18, der wie folgt lautet:

    return n == 0 ? n1 : n2;
    

    Mit diesem Haltepunkt können wir den Programmzustand überprüfen, bevor die Funktion beendet wird. Von unseren bisherigen Haltepunkten in den Zeilen 1 und 13 können wir nichts Neues mehr erfahren, daher löschen wir sie.

  7. Entfernen Sie die vorherigen Haltepunkte aus den Zeilen 1 und 13. Wählen Sie im Randbereich neben den Zeilennummern die Haltepunkte aus, 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

    Wir verstehen nun besser, was vor sich geht, und haben einen Haltepunkt gesetzt, um unser Programm bei fehlerhaftem Verhalten zu erwischen. Wir sollten diesen Fehler nun finden können!

  8. Starten Sie den Debugger ein letztes Mal.

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

    Wir haben ausdrücklich „Fibonacci(5)“ angefordert, aber „Fibonacci(4)“ erhalten, was nicht korrekt ist. 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 unsere for-Schleife-Anweisung ein wenig näher an.

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

    Diese Logik bewirkt, dass das Programm beendet wird, sobald der obere Teil der For-Schleife erkennt, das i n entspricht. Dies bedeutet, dass der Schleifencode in dem Fall, dass i gleich n ist, 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)
    {
        Console.WriteLine("The output is: ");
        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 Sie dies noch nicht getan haben.

  10. Nehmen Sie die oben genannte Änderung in Zeile 11 vor, und belassen Sie den Haltepunkt in Zeile 18.

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

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

    Hallo! Es sieht so aus, als hätten wir es geschafft! 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 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.