Debuggen für absolute Anfänger
Ohne Ausnahme tut der Code, den wir als Softwareentwickler schreiben, nicht immer das, was wir erwartet haben. Manchmal tut es etwas völlig anderes! Wenn das Unerwartete geschieht, besteht die nächste Aufgabe darin, herauszufinden, warum, und obwohl wir möglicherweise versucht werden, nur stundenlang auf unseren Code zu starren, ist es einfacher und effizienter, ein Debuggingtool oder Debugger zu verwenden.
Ein Debugger ist leider nicht etwas, das alle Probleme oder "Fehler" in unserem Code magisch aufdecken kann. Debugging bedeutet, ihren Code schritt für Schritt in einem Debuggingtool wie Visual Studio auszuführen, um den genauen Punkt zu finden, an dem Sie einen Programmierfehler gemacht haben. Dann verstehen Sie, welche Korrekturen Sie in Ihrem Code vornehmen müssen, und Debugging-Tools ermöglichen es oft, temporäre Änderungen vorzunehmen, damit Sie das Programm weiterhin ausführen können.
Die effektive Verwendung eines Debuggers ist auch eine Fähigkeit, die Zeit und Übung benötigt, um zu lernen, ist aber letztendlich eine grundlegende Aufgabe für jeden Softwareentwickler. In diesem Artikel werden die Kernprinzipien des Debuggens vorgestellt und Tipps für die ersten Schritte bereitgestellt.
Klären Sie das Problem, indem Sie sich die richtigen Fragen stellen
Es hilft, das Problem, auf das Sie gestoßen sind, zu klären, bevor Sie versuchen, es zu beheben. Wir erwarten, dass Sie bereits auf ein Problem in Ihrem Code gestoßen sind, sonst wären Sie nicht hier und würden versuchen herauszufinden, wie Sie es debuggen können! Bevor Sie also mit dem Debuggen beginnen, stellen Sie sicher, dass Sie das Problem identifiziert haben, das Sie lösen möchten:
Was haben Sie davon erwartet, dass Ihr Code funktioniert?
Was ist stattdessen passiert?
Wenn beim Ausführen der App ein Fehler (Ausnahme) auftritt, kann dies eine gute Sache sein! Eine Ausnahme ist ein unerwartetes Ereignis, das beim Ausführen von Code auftritt, in der Regel ein Fehler irgendeiner Art. Ein Debuggingtool kann Sie an die genaue Stelle in Ihrem Code bringen, an der die Ausnahme aufgetreten ist, und sie kann Ihnen dabei helfen, mögliche Fixes zu untersuchen.
Wenn etwas anderes passiert ist, was ist das Symptom des Problems? Vermuten Sie bereits, wo dieses Problem in Ihrem Code aufgetreten ist? Wenn ihr Code beispielsweise Text anzeigt, aber der Text falsch ist, wissen Sie, dass ihre Daten schlecht sind oder der Code, der den Anzeigetext festgelegt hat, einen Fehler aufweist. Indem Sie den Code in einem Debugger durchlaufen, können Sie jede und jede Änderung ihrer Variablen untersuchen, um genau zu ermitteln, wann und wie falsche Werte zugewiesen werden.
Überprüfen Sie Ihre Annahmen
Bevor Sie einen Bug oder einen Fehler untersuchen, überlegen Sie sich die Annahmen, die dazu geführt haben, dass Sie ein bestimmtes Ergebnis erwartet haben. Verborgene oder unbekannte Annahmen können das Identifizieren eines Problems verhindern, selbst wenn Sie die Ursache des Problems direkt in einem Debugger betrachten. Möglicherweise haben Sie eine lange Liste möglicher Annahmen! Hier sind einige Fragen, die Sie sich stellen müssen, um Ihre Annahmen herauszufordern.
Verwenden Sie die richtige API (d. r. das richtige Objekt, die richtige Funktion, Methode oder Eigenschaft)? Eine API, die Sie verwenden, tut möglicherweise nicht das, was Sie denken. (Nachdem Sie den API-Aufruf im Debugger untersucht haben, kann es erforderlich sein, die Dokumentation zu konsultieren, um es zu beheben und die korrekte API zu identifizieren.)
Verwenden Sie eine API ordnungsgemäß? Vielleicht haben Sie die richtige API verwendet, sie aber nicht richtig verwendet.
Enthält Ihr Code Tippfehler? Einige Tippfehler, wie eine einfache falsche Schreibweise eines Variablennamens, können schwer zu erkennen sein, besonders wenn man mit Programmiersprachen arbeitet, bei denen keine Variablen deklariert werden müssen, bevor sie verwendet werden.
Haben Sie eine Änderung an Ihrem Code vorgenommen und davon ausgegangen, dass es sich nicht um das Problem bezieht, das Sie sehen?
Haben Sie erwartet, dass ein Objekt oder eine Variable einen bestimmten Wert (oder einen bestimmten Werttyp) enthält, der sich von dem unterscheidet, was wirklich passiert ist?
Kennen Sie die Absicht des Codes? Häufig ist es schwieriger, den Code einer anderen Person zu debuggen. Wenn es sich nicht um Ihren Code handelt, ist es möglich, dass Sie Zeit damit verbringen müssen, genau zu lernen, was der Code tut, bevor Sie ihn effektiv debuggen können.
Tipp
Beginnen Sie beim Schreiben von Code klein und beginnen Sie mit Code, der funktioniert! (Guter Beispielcode ist hier hilfreich.) Manchmal ist es einfacher, einen großen oder komplizierten Codesatz zu beheben, indem er mit einem kleinen Codeteil beginnt, der die Kernaufgabe veranschaulicht, die Sie erreichen möchten. Anschließend können Sie Code inkrementell ändern oder hinzufügen und an jedem Punkt auf Fehler testen.
Indem Sie Ihre Annahmen in Frage stellen, können Sie die Zeit reduzieren, die es dauert, um ein Problem in Ihrem Code zu finden. Sie können auch die Zeit reduzieren, die zum Beheben eines Problems benötigt wird.
Durchlaufen Sie Ihren Code im Debugmodus, um zu ermitteln, wo das Problem aufgetreten ist.
Wenn Sie eine App normalerweise ausführen, werden Fehler und falsche Ergebnisse erst angezeigt, nachdem der Code ausgeführt wurde. Ein Programm kann auch unerwartet beendet werden, ohne Ihnen mitzuteilen, warum.
Wenn Sie eine App in einem Debugger ausführen, auch als Debugmodusbezeichnet, überwacht der Debugger aktiv alles, was während der Ausführung des Programms geschieht. Außerdem können Sie die App jederzeit anhalten, um den Zustand zu untersuchen und dann den Code Zeile für Zeile durchzugehen, um jedes Detail zu verfolgen, während es geschieht.
In Visual Studio wechseln Sie in den Debugmodus, indem Sie F5 nutzen (oder den Menübefehl Debuggen>Debuggen starten oder die Schaltfläche Debuggen starten in der Debug-Symbolleiste). Wenn Ausnahmen auftreten, gelangen Sie mit dem Ausnahmehilfsprogramm von Visual Studio zu dem genauen Punkt, an dem die Ausnahme aufgetreten ist, und stellt weitere hilfreiche Informationen bereit. Weitere Informationen zum Behandeln von Ausnahmen in Ihrem Code finden Sie unter Debugtechniken und Tools.
Wenn Sie keine Ausnahme erhalten haben, haben Sie wahrscheinlich eine gute Vorstellung davon, wo Sie nach dem Problem in Ihrem Code suchen. Bei diesem Schritt verwenden Sie Haltepunkte mit dem Debugger, damit Sie den Code gründlicher untersuchen können. Haltepunkte sind ein einfaches und wichtiges Feature für das zuverlässige Debuggen. Ein Haltepunkt gibt an, wo Visual Studio den ausgeführten Code anhalten soll, damit Sie die Werte von Variablen überprüfen oder das Verhalten des Arbeitsspeichers sowie die Reihenfolge, in der Code ausgeführt wird, beobachten können.
In Visual Studio können Sie schnell einen Haltepunkt festlegen, indem Sie neben einer Codezeile auf den linken Rand klicken. Oder setzen Sie den Cursor auf eine Linie, und drücken Sie F9.
Um diese Konzepte zu veranschaulichen, führen wir Sie durch einen Beispielcode, der bereits mehrere Fehler aufweist. Wir verwenden C#, aber die Debugfeatures gelten für Visual Basic, C++, JavaScript, Python und andere unterstützte Sprachen. Beispielcode für Visual Basic wird ebenfalls bereitgestellt, Screenshots befinden sich jedoch in C#.
Erstellen einer Beispiel-App (mit einigen Fehlern)
Als Nächstes erstellen Sie eine Anwendung mit einigen Fehlern.
Sie müssen Visual Studio installiert haben und die .NET-Desktopentwicklung Workload installiert haben.
Wenn Sie Visual Studio noch nicht installiert haben, wechseln Sie zur Visual Studio-Downloads Seite, um es kostenlos zu installieren.
Wenn Sie die Workload installieren müssen und Visual Studio bereits installiert ist, wählen Sie Extras>Tools und Features abrufen.... Das Visual Studio-Installationsprogramm wird gestartet. Wählen Sie die Workload .NET-Desktopentwicklung und anschließend Ändern aus.
Öffnen Sie Visual Studio.
Wählen Sie im Startfenster Neues Projekt erstellenaus. Geben Sie Konsolen- in das Suchfeld ein, wählen Sie entweder C#- oder Visual Basic- als Sprache aus, und wählen Sie dann Konsolen-App- für .NET aus. Wählen Sie Weiter aus. Geben Sie ConsoleApp_FirstApp als Projektnamen ein, und wählen Sie Nextaus.
Wenn Sie einen anderen Projektnamen verwenden, müssen Sie den Namespacewert so ändern, dass er dem Projektnamen entspricht, wenn Sie den Beispielcode kopieren.
Wählen Sie entweder das empfohlene Zielframework oder .NET 8 aus, und wählen Sie dann Createaus.
Wenn die .NET-Projektvorlage Konsolen-App nicht angezeigt wird, navigieren Sie zu Extras>Tools und Features abrufen..., woraufhin der Visual Studio-Installer geöffnet wird. Wählen Sie die Workload .NET-Desktopentwicklung und anschließend Ändern aus.
Visual Studio erstellt das Konsolenprojekt, das im Projektmappen-Explorer im rechten Bereich angezeigt wird.
Ersetzen Sie in Program.cs (oder Program.vb) den gesamten Standardcode durch den folgenden Code. (Wählen Sie zuerst die richtige Sprachregisterkarte aus, entweder „C#“ oder „Visual Basic“.)
using System; using System.Collections.Generic; namespace ConsoleApp_FirstApp { class Program { static void Main(string[] args) { Console.WriteLine("Welcome to Galaxy News!"); IterateThroughList(); Console.ReadKey(); } private static void IterateThroughList() { var theGalaxies = new List<Galaxy> { new Galaxy() { Name="Tadpole", MegaLightYears=400, GalaxyType=new GType('S')}, new Galaxy() { Name="Pinwheel", MegaLightYears=25, GalaxyType=new GType('S')}, new Galaxy() { Name="Cartwheel", MegaLightYears=500, GalaxyType=new GType('L')}, new Galaxy() { Name="Small Magellanic Cloud", MegaLightYears=.2, GalaxyType=new GType('I')}, new Galaxy() { Name="Andromeda", MegaLightYears=3, GalaxyType=new GType('S')}, new Galaxy() { Name="Maffei 1", MegaLightYears=11, GalaxyType=new GType('E')} }; foreach (Galaxy theGalaxy in theGalaxies) { Console.WriteLine(theGalaxy.Name + " " + theGalaxy.MegaLightYears + ", " + theGalaxy.GalaxyType); } // Expected Output: // Tadpole 400, Spiral // Pinwheel 25, Spiral // Cartwheel, 500, Lenticular // Small Magellanic Cloud .2, Irregular // Andromeda 3, Spiral // Maffei 1, 11, Elliptical } } public class Galaxy { public string Name { get; set; } public double MegaLightYears { get; set; } public object GalaxyType { get; set; } } public class GType { public GType(char type) { switch(type) { case 'S': MyGType = Type.Spiral; break; case 'E': MyGType = Type.Elliptical; break; case 'l': MyGType = Type.Irregular; break; case 'L': MyGType = Type.Lenticular; break; default: break; } } public object MyGType { get; set; } private enum Type { Spiral, Elliptical, Irregular, Lenticular} } }
Unser Ziel für diesen Code ist es, den Galaxiennamen, den Abstand zur Galaxie und den Galaxientyp in einer Liste anzuzeigen. Zum Debuggen ist es wichtig, die Absicht des Codes zu verstehen. Hier ist das Format für eine Zeile aus der Liste, die in der Ausgabe angezeigt werden soll:
Galaxienname, Entfernung, Galaxie Typ.
Ausführen der App
Drücken Sie F5 oder die Schaltfläche Start Debugging in der Debug-Symbolleiste oberhalb des Code-Editors.
Die App wird gestartet, und der Debugger zeigt keine Ausnahmen an. Die im Konsolenfenster angezeigte Ausgabe ist jedoch nicht das, was Sie erwarten. Folgende Ausgabe wird erwartet:
Tadpole 400, Spiral
Pinwheel 25, Spiral
Cartwheel, 500, Lenticular
Small Magellanic Cloud .2, Irregular
Andromeda 3, Spiral
Maffei 1, Elliptical
Stattdessen wird diese Ausgabe angezeigt:
Tadpole 400, ConsoleApp_FirstApp.GType
Pinwheel 25, ConsoleApp_FirstApp.GType
Cartwheel, 500, ConsoleApp_FirstApp.GType
Small Magellanic Cloud .2, ConsoleApp_FirstApp.GType
Andromeda 3, ConsoleApp_FirstApp.GType
Maffei 1, 11, ConsoleApp_FirstApp.GType
Beim Betrachten der Ausgabe und unseres Codes wissen wir, dass GType
der Name der Klasse ist, die den Galaxientyp speichert. Wir versuchen, den tatsächlichen Galaxientyp (z. B. "Spiral") und nicht den Klassennamen anzuzeigen!
Debuggen der App
Fügen Sie einen Haltepunkt ein, während die App noch ausgeführt wird.
Klicken Sie in der
foreach
-Schleife mit der rechten Maustaste neben dieConsole.WriteLine
-Methode, um das Kontextmenü aufzurufen, und wählen Sie aus dem Flyoutmenü Haltepunkt>Haltepunkt einfügen aus.foreach (Galaxy theGalaxy in theGalaxies) { Console.WriteLine(theGalaxy.Name + " " + theGalaxy.MegaLightYears + ", " + theGalaxy.GalaxyType); }
Wenn Sie den Haltepunkt festlegen, wird im linken Rand ein roter Punkt angezeigt.
Wie Sie ein Problem in der Ausgabe sehen, beginnen Sie mit dem Debuggen, indem Sie sich den vorherigen Code ansehen, der die Ausgabe im Debugger festlegt.
Wählen Sie auf der Symbolleiste „Debuggen“ die Schaltfläche Neu starten
(STRG + UMSCHALT + F5).
Die App hält am festgelegten Haltepunkt inne. Die gelbe Hervorhebung gibt an, wo der Debugger angehalten wird (die gelbe Codezeile wurde noch nicht ausgeführt).
Zeigen Sie auf die
GalaxyType
-Variable auf der rechten Seite, und erweitern SietheGalaxy.GalaxyType
auf der linken Seite des Schraubenschlüsselsymbols. Sie sehen, dassGalaxyType
eine EigenschaftMyGType
enthält und der Eigenschaftswert aufSpiral
festgelegt ist.Bei „Spiral“ handelt es sich um den Wert, der eigentlich in der Konsole hätte ausgegeben werden sollen. Daher ist es ein guter Start, dass Sie beim Ausführen der App auf den Wert in diesem Code zugreifen können. In diesem Szenario verwenden wir die falsche API. Sehen wir uns an, ob Sie dies beim Ausführen von Code im Debugger beheben können.
Zeigen Sie in diesem Code während des Debuggens auf das Ende von
theGalaxy.GalaxyType
, und ändern Sie den Wert intheGalaxy.GalaxyType.MyGType
. Obwohl Sie die Änderung vornehmen können, zeigt der Code-Editor einen Fehler an (rote Schlangenlinie). (In Visual Basic wird der Fehler nicht angezeigt, und dieser Codeabschnitt funktioniert.)Drücken Sie F11 (Debuggen>Schritt in oder die Schaltfläche Schritt in auf der Symbolleiste "Debuggen") aus, um die aktuelle Codezeile auszuführen.
Durch F11 durchläuft der Debugger eine Anweisung nach der anderen (und führt deren Code aus). F10 (Step Over) ist ein ähnlicher Befehl, und beide sind nützlich, wenn Sie lernen, wie Sie den Debugger verwenden.
Wenn Sie versuchen, den Debugger zu durchlaufen, wird das Dialogfeld "Hot Reload" angezeigt, das angibt, dass Bearbeitungen nicht kompiliert werden können.
Das Dialogfeld "Bearbeiten und Fortfahren" wird angezeigt, das angibt, dass Bearbeitungen nicht kompiliert werden können.
Anmerkung
Um den Visual Basic-Beispielcode zu debuggen, überspringen Sie die nächsten wenigen Schritte, bis Sie angewiesen sind, auf das Symbol Neu starten
.
Wählen Sie im Meldungsfeld Hot Reload oder Bearbeiten und fortfahren die Option Bearbeiten aus. Eine Fehlermeldung wird nun im Fenster Fehlerliste angezeigt. Der Fehler gibt an, dass die
'object'
keine Definition fürMyGType
enthält.Obwohl wir jede Galaxie mit einem Objekt vom Typ
GType
(das die eigenschaftMyGType
hat) festlegen, erkennt der Debugger dastheGalaxy
Objekt nicht als Objekt vom TypGType
. Was ist los? Sie möchten jeden Code durchsuchen, der den Galaxientyp festlegt. Wenn Sie dies tun, sehen Sie, dass dieGType
Klasse definitiv eine Eigenschaft vonMyGType
hat, aber etwas ist nicht richtig. Die Fehlermeldung überobject
stellt sich als Hinweis dar; für den Sprachdolmetscher scheint der Typ ein Objekt vom Typobject
anstelle eines Objekts vom TypGType
zu sein.Wenn Sie Ihren Code zum Festlegen des Galaxientyps durchsehen, wird die
GalaxyType
-Eigenschaft derGalaxy
-Klasse alsobject
anstelle vonGType
angegeben.public object GalaxyType { get; set; }
Ändern Sie den vorherigen Code wie folgt:
public GType GalaxyType { get; set; }
Wählen Sie auf der Symbolleiste „Debuggen“ Neu starten
(STRG + UMSCHALT + F5) aus, um den Code erneut zu kompilieren und neu zu starten.
Wenn der Debugger nun auf
Console.WriteLine
angehalten wird, können Sie mit der Maus auftheGalaxy.GalaxyType.MyGType
zeigen und sehen, dass der Wert ordnungsgemäß festgelegt ist.Entfernen Sie den Haltepunkt, indem Sie auf den roten Punkt am linken Rand klicken oder mit der rechten Maustaste darauf klicken und Haltepunkt>Haltepunkt entfernen auswählen. Drücken Sie anschließend F5, um den Vorgang fortzusetzen.
Die App wird ausgeführt, und eine Ausgabe wird angezeigt. Es sieht gut aus, aber Sie bemerken eine Sache. Sie haben erwartet, dass die Kleine Magellansche Wolke in der Konsolenausgabe als Unregelmäßige Galaxie angezeigt wird, aber es wird überhaupt kein Galaxientyp angezeigt.
Tadpole 400, Spiral Pinwheel 25, Spiral Cartwheel, 500, Lenticular Small Magellanic Cloud .2, Andromeda 3, Spiral Maffei 1, Elliptical
Legen Sie einen Haltepunkt in dieser Codezeile vor der
switch
-Anweisung (vor derSelect
-Anweisung in Visual Basic) fest.public GType(char type)
Dieser Code ist der Ort, an dem der Galaxientyp festgelegt ist, daher möchten wir es genauer betrachten.
Wählen Sie auf der Symbolleiste „Debuggen“ die Schaltfläche Neu starten
(STRG + UMSCHALT + F5) aus, um einen Neustart durchzuführen.
Der Debugger hält an der Codezeile an, an der Sie den Haltepunkt festlegen.
Zeigen Sie auf die Variable
type
. Es wird ein Wert vonS
angezeigt (entsprechend dem Zeichencode). Sie interessieren sich für einen Wert vonI
, von dem Sie wissen, dass es sich um einen Unregelmäßigen Galaxientyp handelt.Drücken Sie F5, und zeigen Sie erneut auf die
type
-Variable. Wiederholen Sie diesen Schritt, bis in der variablentype
ein Wert vonI
angezeigt wird.Drücken Sie F11 (Debuggen>Einzelschritt).
Drücken Sie F11, bis Sie in der
switch
-Anweisung auf einer Codezeile mit dem Wert 'I' anhalten (Select
-Anweisung für Visual Basic). Hier sehen Sie ein klares Problem, das sich aus einem Tippfehler ergibt. Sie haben erwartet, dass der Code an die Stelle wechselt, an der erMyGType
als unregelmäßigen Galaxientyp festlegt, aber der Debugger überspringt diesen Code stattdessen vollständig und hält im Abschnittdefault
derswitch
-Anweisung (Else
Anweisung in Visual Basic) an.Wenn Sie den Code betrachten, sehen Sie einen Tippfehler in der
case 'l'
-Anweisung. Dort solltecase 'I'
stehen.Wählen Sie den Code für
case 'l'
aus, und ersetzen Sie diesen durchcase 'I'
.Entfernen Sie den Breakpoint und wählen Sie dann die Schaltfläche Neu starten aus, um die App wieder zu starten.
Die Fehler wurden jetzt behoben, und Sie sehen jetzt die Ausgabe, die Sie erwarten!
Drücken Sie eine beliebige Taste, um die App abzuschließen.
Zusammenfassung
Wenn ein Problem auftritt, verwenden Sie den Debugger und Schrittbefehle wie F10- und F11-, um den Codebereich mit dem Problem zu finden.
Anmerkung
Wenn es schwierig ist, den Codebereich zu identifizieren, in dem das Problem auftritt, legen Sie einen Haltepunkt in Code fest, der ausgeführt wird, bevor das Problem auftritt, und verwenden Sie dann Schrittbefehle, bis das Problemmanifest angezeigt wird. Sie können zudem Ablaufverfolgungspunkte verwenden, um Nachrichten im Fenster Ausgabe zu protokollieren. Wenn Sie protokollierte Nachrichten betrachten (und feststellen, welche Nachrichten noch nicht protokolliert wurden!), können Sie den Codebereich häufig mit dem Problem isolieren. Möglicherweise müssen Sie diesen Vorgang mehrmals wiederholen, um ihn einzugrenzen.
Wenn Sie den Codebereich mit dem Problem finden, verwenden Sie den Debugger, um zu untersuchen. Um die Ursache eines Problems zu finden, überprüfen Sie den Problemcode beim Ausführen der App im Debugger:
Überprüfen sie Variablen, und überprüfen Sie, ob sie den Typ von Werten enthalten, die sie enthalten sollen. Wenn Sie einen ungültigen Wert finden, finden Sie heraus, wo der ungültige Wert festgelegt wurde (um zu ermitteln, wo der Wert festgelegt wurde, müssen Sie den Debugger möglicherweise neu starten, sich den Aufrufstapeloder beides ansehen).
Überprüfen Sie, ob die Anwendung den erwarteten Code ausführt. (In der Beispielanwendung wurde erwartet, dass der Code für die
switch
-Anweisung den Galaxientyp auf "Unregelmäßig" festlegt, jedoch hat die App diesen Code aufgrund des Tippfehlers übersprungen.)
Tipp
Sie verwenden einen Debugger, um Fehler zu finden. Ein Debuggingtool kann Fehler für Sie nur finden, wenn es die Absicht Ihres Codes kennt. Ein Tool kann nur die Absicht Ihres Codes kennen, wenn Sie, der Entwickler, diese Absicht ausdrücken. Dies erreichen Sie mit dem Schreiben von Komponententests.
Nächste Schritte
In diesem Artikel haben Sie einige allgemeine Debugkonzepte kennengelernt. Als Nächstes können Sie mehr über den Debugger erfahren.