Wird geladen...

Debugging-Techniken in C#

Lernen Sie Debugging-Techniken in C# mit Breakpoints und Analyse-Tools zur schnellen Fehlerbehebung.

Im Softwareentwicklungsprozess ist Debugging (Fehlerbehebung) ein systematischer Vorgang, bei dem das unerwartete Verhalten eines Programms analysiert und fehlerhafter Code identifiziert wird. In C# bieten Tools wie Visual Studio und Visual Studio Code leistungsstarke Debugging-Funktionen, die es Entwicklern ermöglichen, den Programmablauf Schritt für Schritt zu verfolgen, Variablenwerte zu prüfen und den Programmfluss zu analysieren.


Unterschied zwischen Debug- und Release-Modus

.NET-Projekte verfügen über zwei Haupt-Build-Konfigurationen:


// In Visual Studio über das obere Menü auswählbar:
// [Debug ▼] → [Release]

Im Debug-Modus kann das Programm Zeile für Zeile ausgeführt werden, was volle Kontrolle über den Codefluss ermöglicht.


Haltepunkte (Breakpoints)

Ein Breakpoint ist ein Marker, der das Programm an einer bestimmten Zeile anhält. Dadurch läuft das Programm bis zu dieser Zeile und pausiert, sodass alle aktuellen Variablenwerte überprüft werden können.


class Program
{
    static void Main()
    {
        int a = 5;
        int b = 0;
        int c = a / b; // Fehler: DivideByZeroException
        Console.WriteLine(c);
    }
}

Im obigen Beispiel kann ein Breakpoint an der Zeile int c = a / b; gesetzt werden, um das Programm dort anzuhalten und die Werte von a und b im Fenster „Locals“ zu überprüfen.


Schrittweise Ausführung (Stepping)

In Visual Studio können folgende Tastenkombinationen zum schrittweisen Ausführen des Codes verwendet werden:

Mit diesen Werkzeugen lässt sich der Programmfluss genau steuern und die Ursache eines Fehlers präzise lokalisieren.


Variablenüberwachung (Watch- & Autos-Fenster)

Visual Studio bietet die Möglichkeit, Variablenwerte während des Debuggens in Echtzeit zu überwachen:

Wenn Sie den Mauszeiger über eine Variable bewegen, wird ihr aktueller Wert in einem Tooltip angezeigt.


Verwendung von Immediate und Watch

Das Immediate Window ermöglicht es, während des Debuggens Code auszuführen. Sie können Variablenwerte ändern oder kurze Ausdrücke testen, ohne das Programm neu zu starten.


// Beispiel für Immediate Window:
// ? a + b
// ? myList.Count
// a = 25

So können Sie Berechnungen testen oder Variablenwerte anpassen, ohne die Anwendung zu beenden.


Bedingte Haltepunkte (Conditional Breakpoints)

Manchmal soll das Programm nicht bei jeder Iteration anhalten, sondern nur bei bestimmten Bedingungen. Dafür können Sie einen bedingten Breakpoint verwenden.


for (int i = 0; i < 100; i++)
{
    Console.WriteLine(i);
}

Wenn Sie in dieser Schleife einen Breakpoint setzen und im Menü „Conditions“ die Bedingung i == 50 eingeben, hält das Programm nur beim 50. Durchlauf an.


Exception Settings (Fehlerbehandlungseinstellungen)

Unter Debug → Windows → Exception Settings können Sie festlegen, bei welchen Fehlertypen das Programm anhalten soll. Zum Beispiel können Sie einstellen, dass nur bei NullReferenceException oder InvalidOperationException gestoppt wird.

Diese Funktion verhindert unnötige Unterbrechungen in komplexen Anwendungen.


Debugging innerhalb von Try / Catch-Blöcken

Selbst wenn Fehler innerhalb eines try / catch-Blocks abgefangen werden, kann Visual Studio – sofern „Break on User-Unhandled Exceptions“ aktiviert ist – an der Zeile anhalten, in der die Ausnahme auftritt.


try
{
    int[] array = new int[3];
    array[5] = 10; // IndexOutOfRangeException
}
catch (Exception ex)
{
    Console.WriteLine("Fehler abgefangen: " + ex.Message);
}

So können Sie den Zustand der Anwendung unmittelbar vor dem Auftreten der Ausnahme untersuchen.


Verwendung von Debug.WriteLine()

Die Methode Debug.WriteLine() schreibt Informationsmeldungen während des Debuggens in das Ausgabefenster (Output Window). Dies ist nützlich, um Protokolle im Hintergrund zu führen, ohne die Konsolenausgabe zu verändern.


using System.Diagnostics;

class Program
{
    static void Main()
    {
        for (int i = 0; i < 3; i++)
        {
            Debug.WriteLine($"Schritt {i} abgeschlossen.");
        }
        Console.WriteLine("Programm beendet.");
    }
}

Diese Meldungen sind nur im Debug-Modus sichtbar und werden in der Release-Version nicht ausgeführt.


Logging und Fehlerüberwachung

Debugging dient nicht nur der sofortigen Analyse, sondern auch der langfristigen Überwachung einer Anwendung. Dafür können Logging-Bibliotheken wie Serilog, NLog oder Microsoft.Extensions.Logging verwendet werden.


using Microsoft.Extensions.Logging;

class Program
{
    static void Main()
    {
        using var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder.AddConsole();
        });
        var logger = loggerFactory.CreateLogger<Program>();

        try
        {
            int a = 10, b = 0;
            int c = a / b;
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Ein Fehler ist aufgetreten!");
        }
    }
}

Logging ermöglicht die Nachverfolgung von Fehlern nicht nur während der Entwicklung, sondern auch in produktiven Systemen.


Beispiel: Debugging eines Benutzer-Logins

Das Programm hält an der Stelle an, an der der Breakpoint gesetzt wurde.

Breakpoint in Codezeilen

Im folgenden Beispiel wird ein Fehler in einem Benutzeranmeldeformular Schritt für Schritt mit dem Debugger untersucht.


class LoginService
{
    public bool Login(string username, string password)
    {
        if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            throw new ArgumentException("Benutzername oder Passwort darf nicht leer sein.");

        return username == "admin" && password == "1234";
    }
}

class Program
{
    static void Main()
    {
        var service = new LoginService();
        Console.Write("Benutzername: ");
        string? u = Console.ReadLine();
        Console.Write("Passwort: ");
        string? p = Console.ReadLine();

        try
        {
            bool result = service.Login(u, p);
            Console.WriteLine(result ? "Login erfolgreich" : "Ungültige Anmeldedaten");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Fehler: {ex.Message}");
        }
    }
}

Du kannst einen Breakpoint auf jede beliebige Zeile setzen und Variablen Schritt für Schritt untersuchen.

Debugging von Codezeilen

Wenn du einen Breakpoint auf die return-Zeile setzt, kannst du die Werte von username und password in Echtzeit überprüfen und analysieren, warum die Bedingung false zurückgibt.


Best Practices


TL;DR

  • Debugging: Der Prozess, den Programmablauf Schritt für Schritt zu verfolgen, um Fehler zu finden.
  • Breakpoint: Hält die Ausführung an einer bestimmten Codezeile an.
  • Watch & Immediate: Werkzeuge zur Überwachung von Variablen und zum sofortigen Ausführen von Code.
  • Debug.WriteLine: Entwicklerbezogene Protokollausgabe (nur im Debug-Modus).
  • Logging: Zeichnet Fehler und Ereignisse auf, auch in Produktionsumgebungen.
  • Bedingte Breakpoints: Stoppen nur unter bestimmten Bedingungen und verbessern die Effizienz.

Ähnliche Artikel