Freigeben über


Ausnahmebehandlung (C#-Programmierhandbuch)

Ein Try-Block wird von C#-Programmierern verwendet, um Code zu partitionieren, der von einer Ausnahme betroffen sein kann. Zugeordnete Catch-Blöcke werden verwendet, um alle resultierenden Ausnahmen zu behandeln. Ein abschließender Block enthält Code, der ausgeführt wird, unabhängig davon, ob eine Ausnahme im try Block ausgelöst wird, z. B. das Freigeben von Ressourcen, die im try Block zugeordnet sind. Ein try Block erfordert einen oder mehrere zugeordnete catch Blöcke oder einen finally Block oder beides.

Die folgenden Beispiele zeigen eine try-catch Anweisung, eine try-finally Anweisung und eine try-catch-finally Anweisung.

try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
    // Only catch exceptions that you know how to handle.
    // Never catch base class System.Exception without
    // rethrowing it at the end of the catch block.
}
try
{
    // Code to try goes here.
}
finally
{
    // Code to execute after the try block goes here.
}
try
{
    // Code to try goes here.
}
catch (SomeSpecificException ex)
{
    // Code to handle the exception goes here.
}
finally
{
    // Code to execute after the try (and possibly catch) blocks
    // goes here.
}

Ein try Block ohne einen catchfinally Block verursacht einen Compilerfehler.

catch-Blöcke

Ein catch Block kann den Typ der abzufangenden Ausnahme angeben. Die Typspezifikation wird als Ausnahmefilter bezeichnet. Der Ausnahmetyp sollte von Exception abgeleitet werden. Geben Sie im Allgemeinen nicht Exception als Ausnahmefilter an, es sei denn, Sie wissen, wie alle Ausnahmen behandelt werden können, die möglicherweise im try Block ausgelöst werden, oder Sie haben eine throw Anweisung am Ende Ihres catch Blocks eingefügt.

Mehrere catch Blöcke mit unterschiedlichen Ausnahmeklassen können miteinander verkettet werden. Die catch Blöcke werden von oben nach unten im Code ausgewertet, aber für jede Ausnahme, die ausgelöst wird, wird nur ein catch Block ausgeführt. Der erste catch Block, der den genauen Typ oder eine Basisklasse der ausgelösten Ausnahme angibt, wird ausgeführt. Wenn kein catch Block eine übereinstimmende Ausnahmeklasse angibt, wird ein catch Block ausgewählt, der keinen Typ aufweist, wenn eine in der Anweisung vorhanden ist. Es ist wichtig, Blöcke zuerst mit den spezifischsten (d. h. den abgeleiteten) Ausnahmeklassen zu positionieren catch .

Fangen Sie Ausnahmen ab, wenn die folgenden Bedingungen erfüllt sind:

  • Sie haben ein gutes Verständnis dafür, warum die Ausnahme ausgelöst werden kann, und Sie können eine bestimmte Wiederherstellung implementieren, z. B. die Aufforderung des Benutzers, einen neuen Dateinamen einzugeben, wenn Sie ein FileNotFoundException Objekt erfassen.
  • Sie können eine neue, spezifischere Ausnahme erstellen und auslösen.
    int GetInt(int[] array, int index)
    {
        try
        {
            return array[index];
        }
        catch (IndexOutOfRangeException e)
        {
            throw new ArgumentOutOfRangeException(
                "Parameter index is out of range.", e);
        }
    }
    
  • Sie möchten eine Ausnahme teilweise behandeln, bevor Sie sie zur weiteren Behandlung weitergeben. Im folgenden Beispiel wird ein catch Block verwendet, um dem Fehlerprotokoll vor dem erneuten Auslösen der Ausnahme einen Eintrag hinzuzufügen.
    try
    {
        // Try to access a resource.
    }
    catch (UnauthorizedAccessException e)
    {
        // Call a custom error logging procedure.
        LogError(e);
        // Re-throw the error.
        throw;
    }
    

Sie können auch Ausnahmefilter angeben, um einer Catch-Klausel einen booleschen Ausdruck hinzuzufügen. Ausnahmefilter deuten darauf hin, dass eine bestimmte Catch-Klausel nur übereinstimmt, wenn diese Bedingung wahr ist. Im folgenden Beispiel verwenden beide Catch-Klauseln dieselbe Ausnahmeklasse, aber eine zusätzliche Bedingung wird überprüft, um eine andere Fehlermeldung zu erstellen:

int GetInt(int[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (IndexOutOfRangeException e) when (index < 0) 
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be negative.", e);
    }
    catch (IndexOutOfRangeException e)
    {
        throw new ArgumentOutOfRangeException(
            "Parameter index cannot be greater than the array size.", e);
    }
}

Ein Ausnahmefilter, der immer zurückgegeben false wird, kann verwendet werden, um alle Ausnahmen zu untersuchen, aber nicht zu verarbeiten. Eine typische Verwendung besteht darin, Ausnahmen zu protokollieren:

public class ExceptionFilter
{
    public static void Main()
    {
        try
        {
            string? s = null;
            Console.WriteLine(s.Length);
        }
        catch (Exception e) when (LogException(e))
        {
        }
        Console.WriteLine("Exception must have been handled");
    }

    private static bool LogException(Exception e)
    {
        Console.WriteLine($"\tIn the log routine. Caught {e.GetType()}");
        Console.WriteLine($"\tMessage: {e.Message}");
        return false;
    }
}

Die LogException Methode gibt immer false zurück, da keine catch Klausel zu diesem Ausnahmefilter passt. Die Catch-Klausel kann allgemein sein und System.Exception verwenden. Spätere Klauseln können spezifischere Ausnahmeklassen verarbeiten.

Finally-Blöcke

Mit einem finally Block können Sie Aktionen bereinigen, die in einem try Block ausgeführt werden. Wenn vorhanden, wird der finally Block zuletzt ausgeführt, nach dem try Block und jedem übereinstimmenen catch Block. Ein finally Block wird immer ausgeführt, unabhängig davon, ob eine Ausnahme ausgelöst wird oder ob ein Block catch gefunden wird, der dem Ausnahmetyp entspricht.

Der finally Block kann verwendet werden, um Ressourcen wie Dateidatenströme, Datenbankverbindungen und Grafikhandles freizugeben, ohne auf den Garbage Collector in der Laufzeit zu warten, um die Objekte abzuschließen.

Im folgenden Beispiel wird der finally Block verwendet, um eine Datei zu schließen, die im try Block geöffnet wird. Beachten Sie, dass der Status des Dateihandle überprüft wird, bevor die Datei geschlossen wird. Wenn der try Block die Datei nicht öffnen kann, hat das Dateihandle weiterhin den Wert null , und der finally Block versucht nicht, sie zu schließen. Wenn die Datei stattdessen erfolgreich im try Block geöffnet wird, schließt der finally Block die geöffnete Datei.

FileStream? file = null;
FileInfo fileinfo = new System.IO.FileInfo("./file.txt");
try
{
    file = fileinfo.OpenWrite();
    file.WriteByte(0xF);
}
finally
{
    // Check for null because OpenWrite might have failed.
    file?.Close();
}

C#-Sprachspezifikation

Weitere Informationen finden Sie unter Exceptions and The try statement in the C# Language Specification. Die Sprachspezifikation ist die endgültige Quelle für C#-Syntax und -Verwendung.

Siehe auch