IRONSOFTWAREHOME

C#-Ausnahmebehandlung

C# Ausnahmebehandlung

Tim Corey

59m 46s

Die Behandlung von Ausnahmen ist ein entscheidender Aspekt der robusten Anwendungsentwicklung. Tim Coreys Video zu "Handling Exceptions in C# - When to catch them, where to catch them, and how to catch them" erklärt ausführlich, was Exceptions sind, wie und wo man sie behandelt.

Dieser Artikel soll die Ausnahmebehandlung in C# anhand des Videos von Tim Corey erklären. Es ist eine leistungsstarke Funktion, die es Entwicklern ermöglicht, Fehler und außergewöhnliche Bedingungen zu verwalten, die während der Programmausführung auftreten. Mit den try-, catch- und finally-Blöcken bietet C# eine strukturierte Möglichkeit, Laufzeitfehler zu behandeln, Ausnahmen zu protokollieren und den Programmfluss aufrechtzuerhalten.

Einführung

Tim beginnt mit der Erklärung, dass viele Entwickler eine falsche Vorstellung von Ausnahmen und deren Behandlung haben. Er betont, wie wichtig es ist, zu verstehen, was Ausnahmen sind und wo und wie man sie richtig behandelt, um robustere Anwendungen zu erstellen.

Erstellung einer Demo-Konsolenanwendung

Tim erstellt eine Konsolenanwendung in Visual Studio 2017, um die Behandlung von Ausnahmen zu demonstrieren. Er empfiehlt die Verwendung von Konsolenanwendungen für das Testen neuer Themen, da sie nur minimale Einstellungen erfordern und einfach zu handhaben sind.

using System;

namespace ExceptionsDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // Placeholder for input and output operations
            Console.ReadLine();
        }
    }
}

Erstellen einer Klassenbibliothek

Tim fügt der Lösung eine Klassenbibliothek hinzu, um ein reales Szenario zu simulieren, in dem sich verschiedene Methoden gegenseitig aufrufen.

Er löscht die Standardklasse und erstellt eine neue Klasse namens DemoCode.

public class DemoCode
{
    // Method to retrieve a number based on the provided position
    public int GetNumber(int position)
    {
        int[] numbers = { 1, 4, 7, 2 };
        return numbers[position];
    }

    // Intermediate method calls GetNumber
    public int ParentMethod(int position)
    {
        return GetNumber(position);
    }

    // Top-level method calls ParentMethod
    public int GrandparentMethod(int position)
    {
        return ParentMethod(position);
    }
}

Die Klasse DemoCode enthält Methoden, die sich gegenseitig aufrufen und schließlich eine Zahl aus einem Array auf der Grundlage der angegebenen Position abrufen.

Eine Ausnahme simulieren

Tim erklärt, dass die Anwendung eher Misserfolge als Erfolge aufzeigen soll. Er führt eine Out-of-Bounds-Exception ein, indem er eine ungültige Position an die GrandparentMethod übergibt.

DemoCode demo = new DemoCode();
int result = demo.GrandparentMethod(4); // This will cause an IndexOutOfRangeException
Console.WriteLine($"The value at the given position is {result}");

Die Ausführung des obigen Codes mit einer ungültigen Position führt zu einer IndexOutOfRangeException. Tim zeigt, wie der Visual Studio Debugger das Problem hervorhebt und detaillierte Informationen über die Ausnahme liefert.

Wie man try-catch NICHT verwendet

Tim erklärt einen häufigen Fehler, den Entwickler machen, wenn sie zum ersten Mal etwas über try-catch-Blöcke lernen. Sie umschließen oft den gesamten Codeblock, in dem sie eine Ausnahme erwarten, was zu einer unsachgemäßen Behandlung führen kann.

try
{
    int output = 0;
    output = numbers[position];
    return output;
}
catch (Exception ex)
{
    // Avoid returning default values that can mask the problem
    return 0;
}

Tim betont, dass dieser Ansatz problematisch ist, weil er die Ausnahme versteckt und die Ausführung mit falschen Annahmen fortsetzt. Beispielsweise ist die Angabe von 0 als Standardwert nicht angemessen und kann zu weiteren Problemen führen.

Korrekte Ausnahmebehandlung

Tim betont, dass Ausnahmen wichtige Informationen über unerwartete Zustände in der Anwendung liefern. Wenn die Anwendung in einem solchen Zustand weiterläuft, kann dies zu weiteren Fehlern und Datenbeschädigungen führen.

Anstatt Ausnahmen zu schlucken, ist es wichtig, sie angemessen zu behandeln. Hier ist ein besserer Ansatz:

try
{
    return numbers[position];
}
catch (Exception ex)
{
    // Log the exception or handle it appropriately
    Console.WriteLine(ex.Message);
    throw; // Re-throw the exception to be handled by a higher-level handler
}

Indem Sie die Ausnahme erneut auslösen, stellen Sie sicher, dass das Problem weitergegeben wird und bei Bedarf auf einer höheren Ebene behandelt werden kann.

Nützliche Informationen für den Benutzer

Tim erklärt, dass einige Ausnahmen zwar elegant behandelt werden können, ohne die Anwendung zum Absturz zu bringen, es aber wichtig ist, dem Benutzer nützliches Feedback zu geben. Zum Beispiel die Anzeige eines Nachrichtenfeldes oder einer Benachrichtigung mit der Option, den Vorgang zu wiederholen.

Weitere nützliche Informationen: StackTrace

Tim demonstriert, wie man die StackTrace-Eigenschaft des Ausnahmeobjekts verwendet, um detaillierte Informationen darüber zu erhalten, wo die Ausnahme aufgetreten ist. Dazu gehören die Klassen-, Methoden- und Zeilennummern, die für die Fehlersuche von unschätzbarem Wert sind.

try
{
    return numbers[position];
}
catch (Exception ex)
{
    Console.WriteLine(ex.StackTrace);
    throw;
}

Die StackTrace-Eigenschaft liefert eine vollständige Aufzeichnung des Aufrufstapels und hilft den Entwicklern, den genauen Ort des Problems zu bestimmen.

Proper Platzierung von try-catch

Tim erklärt, dass es beim richtigen Umgang mit Ausnahmen nicht nur darum geht, sie abzufangen, sondern auch darum, zu wissen, wo man seine try-catch-Blöcke platziert. Der Schlüssel liegt darin, try-catch-Blöcke auf einer Ebene zu platzieren, auf der Sie genügend Kontext haben, um die Ausnahme angemessen zu behandeln.

Beispiel für unsachgemäße Platzierung

Wenn Sie einen Try-Catch-Block tief im Aufrufstapel platzieren, können Sie die Ausnahme oft nicht effektiv behandeln, weil Ihnen der Kontext der übergeordneten Operationen fehlt.

// Deep level exception handling (not ideal)
try
{
    return numbers[position];
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
    throw;
}

Beispiel für die korrekte Platzierung

Durch die Platzierung des try-catch-Blocks auf der obersten Ebene, z. B. in der Benutzeroberfläche oder am Einstiegspunkt der Anwendung, können Sie Ausnahmen mit dem vollständigen Kontext der Operation behandeln.

try
{
    int result = demo.GrandparentMethod(4); // This will cause an IndexOutOfRangeException
    Console.WriteLine($"The value at the given position is {result}");
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
    Console.WriteLine(ex.StackTrace);
}

Auf diese Weise können Sie dem Benutzer informativere Meldungen geben und entscheiden, ob die Anwendung weiterlaufen kann oder ob sie beendet werden sollte.

Stack-Trace-Informationen

Tim unterstreicht die Bedeutung von Stack-Trace-Informationen bei der Diagnose von Ausnahmen. Die Stapelverfolgung bietet einen detaillierten Aufrufverlauf, der zeigt, wo die Ausnahme aufgetreten ist und welche Kette von Methodenaufrufen zu ihr geführt hat.

try
{
    int result = demo.GrandparentMethod(4); // This will cause an IndexOutOfRangeException
    Console.WriteLine($"The value at the given position is {result}");
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
    Console.WriteLine(ex.StackTrace);
}

Diese Ausgabe gibt die genaue Position der Ausnahme und den Pfad durch den Code an, was die Fehlersuche und -behebung erleichtert.

Demonstration der Handhabungslogik

Tim zeigt, wie man mit Logik auf der entsprechenden Ebene umgeht. Wenn eine Methode beispielsweise für das Öffnen und Schließen einer Datenbankverbindung zuständig ist, sollte sie Ausnahmen behandeln, um sicherzustellen, dass die Ressourcen richtig verwaltet werden.

public int GrandparentMethod(int position)
{
    try
    {
        Console.WriteLine("Open database connection");
        int output = ParentMethod(position);
        Console.WriteLine("Close database connection");
        return output;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        throw; // Ensure the exception is propagated
    }
}

Wenn in diesem Beispiel eine Ausnahme auftritt, wird die Datenbankverbindung nicht ordnungsgemäß geschlossen, was zu möglichen Ressourcenverlusten führt. Durch Hinzufügen eines try-catch-Blocks können Sie sicherstellen, dass die Verbindung auch dann geschlossen wird, wenn eine Ausnahme auftritt.

Verwendung des finally Block

Tim stellt den finally-Block vor, der sicherstellt, dass ein bestimmter Code unabhängig davon ausgeführt wird, ob eine Ausnahme auftritt. Dies ist besonders nützlich für die Bereinigung von Ressourcen, wie z. B. das Schließen von Datenbankverbindungen.

public int GrandparentMethod(int position)
{
    try
    {
        Console.WriteLine("Open database connection");
        int output = ParentMethod(position);
        return output;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        throw; // Re-throw the exception to ensure it's handled by a higher-level handler
    }
    finally
    {
        Console.WriteLine("Close database connection");
    }
}

Der finally-Block wird nach den try- und catch-Blöcken ausgeführt, um sicherzustellen, dass die Verbindung geschlossen wird, auch wenn eine Ausnahme ausgelöst wird.

Die Wurfaussage

Tim erklärt, wie wichtig es ist, Ausnahmen erneut auszulösen, um sie im Call Stack weiterzuleiten. Auf diese Weise können übergeordnete Handler die Ausnahmen angemessen verarbeiten.

catch (Exception ex)
{
    Console.WriteLine(ex.Message);
    throw; // Re-throws the exception to be handled by the calling method
}

Wiederholung der Ausnahme mit throw; die Übersetzung stellt sicher, dass der vollständige Stack-Trace erhalten bleibt, der einen wertvollen Kontext für die Fehlersuche bietet.

Ausnahmen richtig aufbauschen

Tim demonstriert, wie sich Ausnahmen durch den Aufrufstapel nach oben schieben. Jede Methode prüft auf einen Try-Catch-Block und behandelt die Ausnahme entweder selbst oder übergibt sie an den Aufrufer.

try
{
    int result = demo.GrandparentMethod(4); // This will cause an IndexOutOfRangeException
    Console.WriteLine($"The value at the given position is {result}");
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
    Console.WriteLine(ex.StackTrace);
}

In diesem Beispiel fängt die GrandparentMethod die Ausnahme ab, protokolliert sie und löst sie erneut aus. Der try-catch-Block auf oberster Ebene in der Konsolenanwendung behandelt dann die Ausnahme und zeigt die Fehlermeldung und den Stack-Trace an.

Gängige Fehler bei der Behandlung von Ausnahmen

Tim hebt mehrere häufige Fehler hervor, die Entwickler bei der Behandlung von Ausnahmen machen:

  1. Verwendung throw ex;:

    • Das Umschreiben des Stacktrace und der Verlust von wertvollem Kontext.

    • Beispiel:

    catch (Exception ex)
    {
        // Incorrect
        throw ex; // Rewrites stack trace
    }
    C#
  2. Werfen einer neuen Ausnahme:

    • Erstellen einer neuen Ausnahme mit einer benutzerdefinierten Meldung, wobei die ursprüngliche Stack-Trace verloren geht.

    • Beispiel:

    catch (Exception ex)
    {
        // Incorrect
        throw new Exception("I blew up");
    }
    C#

Erstellen einer neuen Exception ohne Verlust des ursprünglichen Stack Trace

Tim erklärt, wie man eine neue Ausnahme erstellt und dabei den ursprünglichen Stack-Trace beibehält. Dies kann nützlich sein, wenn Sie eine aussagekräftigere Fehlermeldung oder einen anderen Ausnahmetyp bereitstellen möchten, ohne dabei den Kontext des ursprünglichen Fehlers zu vernachlässigen.

catch (Exception ex)
{
    throw new ArgumentException("You passed in bad data", ex);
}

Durch die Übergabe der ursprünglichen Ausnahme (ex) als innere Ausnahme bleibt der ursprüngliche Stack-Trace erhalten, der für die Fehlersuche entscheidend ist.

Bewahren von Stack-Trace-Informationen

Tim demonstriert, wie man beim Erstellen einer neuen Ausnahme auf die ursprüngliche Ausnahmemeldung und den Stack-Trace zugreift.

catch (Exception ex)
{
    Console.WriteLine("You passed in bad data");
    Console.WriteLine(ex.StackTrace);
    throw new ArgumentException("You passed in bad data", ex);
}

Dadurch wird sichergestellt, dass die Ausnahme, die den Stack hinaufgeworfen wird, sowohl die neue Nachricht als auch die ursprünglichen Ausnahmedetails enthält.

Schleifen durch innere Ausnahmen

Tim bietet eine Methode zum Durchlaufen aller inneren Ausnahmen, um deren Meldungen und Stack Traces zu extrahieren.

catch (Exception ex)
{
    Exception inner = ex;
    while (inner != null)
    {
        Console.WriteLine(inner.StackTrace);
        inner = inner.InnerException;
    }
    throw;
}

Diese Schleife durchläuft jede innere Ausnahme und gibt deren Stack-Trace aus, um sicherzustellen, dass alle Ebenen von Ausnahmen berücksichtigt werden.

Unterschiedliche Ausnahmen unterschiedlich behandeln

Tim erörtert, wie man verschiedene Arten von Ausnahmen mit mehreren Catch-Blöcken behandelt. Dies ermöglicht eine spezifische Behandlung je nach Ausnahmetyp.

try
{
    // Code that might throw an exception
}
catch (ArgumentException ex)
{
    Console.WriteLine("You gave us bad information. Bad user!");
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
    Console.WriteLine(ex.StackTrace);
}

In diesem Beispiel wird ArgumentException speziell behandelt, indem eine benutzerdefinierte Meldung ausgegeben wird, während alle anderen Ausnahmen auf einen allgemeinen Handler zurückgreifen, der die Ausnahmemeldung und den Stack-Trace ausgibt.

Bedeutung der Reihenfolge in mehreren Catch-Blöcken

Tim betont, wie wichtig die Reihenfolge bei der Verwendung mehrerer Catch-Blöcke ist. Die spezifischsten Ausnahmen sollten zuerst abgefangen werden, gefolgt von allgemeineren Ausnahmen.

try
{
    // Code that might throw an exception
}
catch (ArgumentException ex)
{
    Console.WriteLine("You gave us bad information. Bad user!");
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
    Console.WriteLine(ex.StackTrace);
}

Wenn ein allgemeinerer Catch-Block vor einem spezifischen Block erscheint, fängt er alle Ausnahmen ab, und der spezifische Catch-Block wird nie erreicht, was zu Kompilierungsfehlern führt.

Abschluss

Tim Coreys fortgeschrittener Video-Leitfaden zur Ausnahmebehandlung in C# deckt wichtige Techniken für die Erstellung neuer Ausnahmen, die Beibehaltung von Stack Traces und die effektive Verwendung mehrerer Catch-Blöcke ab. Indem sie seine Best Practices befolgen, können Entwickler robuste Anwendungen erstellen, die Ausnahmen zuverlässig behandeln und wertvolle Debugging-Informationen liefern.

Earn More by Sharing What You Love

Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Let's Stay in Touch!

Join our newsletter, you’ll get exclusive access on article updates. We value your privacy

Key in blue circle

Holen Sie sich sofort Ihren kostenlosen 30-Tage-Testschlüssel.

Your trial license will be sent to your email address

Keine Einschränkungen. 100 % freigeschaltet. Keine Kreditkarte.

OR
bullet_checkedIhr Testlizenzschlüssel wurde Ihnen per E-Mail gesendet.Keine Einschränkungen. 100 % freigeschaltet. Keine Kreditkarte.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried Iron Suite
Erhalten Sie Ihre unverbindliche Beratung
Füllen Sie das Formular unten aus oder senden Sie eine E-Mail an sales@ironsoftware.com
Ihre Daten werden immer vertraulich behandelt.
Von Millionen von Ingenieur*innen weltweit vertraut
Kundenlogos von Iron Software
Erhalten Sie sofort Ihren kostenlosen 30-Tage-Testschlüssel.
Ihr Testlizenzschlüssel wurde Ihnen per E-Mail gesendet.