try-catch (C#-Referenz)

Die try-catch-Anweisung besteht aus einem try-Block, auf den eine oder mehrere catch-Klauseln folgen, die Handler für verschiedene Ausnahmen angeben.

Hinweise

Beim Auslösen einer Ausnahme sucht die CLR (Common Language Runtime) nach der catch-Anweisung, die diese Ausnahme behandelt. Falls die derzeit ausgeführte Methode keinen solchen catch-Block enthält, sucht die CLR nach der Methode, mit der die aktuelle Methode aufgerufen wurde, usw. bis zur nächsten Aufruflsite. Wird kein catch-Block gefunden, zeigt die CLR eine nicht bearbeitete Ausnahmemeldung für den Benutzer an und hält die Ausführung des Programms an.

Der try-Block enthält den überwachten Code, der möglicherweise die Ausnahme verursacht. Der Block wird solange ausgeführt, bis er erfolgreich abgeschlossen oder eine Ausnahme ausgelöst wird. Der folgende Versuch, ein null-Objekt umzuwandeln, löst z. B. die NullReferenceException-Ausnahme aus:

object o2 = null;
try
{
    int i2 = (int)o2;   // Error
}

Obwohl die catch-Klausel ohne Argumente verwendet wird, sodass sie jeden Ausnahmetyp abfängt, wird dies nicht empfohlen. Im Allgemeinen sollten Sie nur jene Ausnahmen abfangen, die Sie wiederherstellen können. Deshalb sollten Sie immer ein von Exception abgeleitetes Objektargument angeben:

catch (InvalidCastException e) 
{
}

Es darf mehr als eine bestimmte catch-Klausel in derselben try-catch-Anweisung verwendet werden. In diesem Fall ist die Reihenfolge der catch-Klauseln von Bedeutung, da die catch-Klauseln nacheinander überprüft werden. Präziser definierte Ausnahmen sollten vor weniger präzisen abgefangen werden. Der Compiler erzeugt einen Fehler, wenn Sie Ihre catch-Blöcke so anordnen, dass ein Block, der sich weiter unten befindet, nie erreicht werden kann.

Mit einer throw-Anweisung kann in einem catch-Block die Ausnahme erneut ausgelöst werden, die von der catch-Anweisung abgefangen wird. Im folgenden Beispiel werden Quellinformationen aus einer IOException-Ausnahme extrahiert, und anschließend wird die Ausnahme in der übergeordneten Methode ausgelöst.

catch (FileNotFoundException e)
{
    // FileNotFoundExceptions are handled here.
}
catch (IOException e)
{
    // Extract some information from this exception, and then 
    // throw it to the parent method.
    if (e.Source != null)
        Console.WriteLine("IOException source: {0}", e.Source);
    throw;
}

Sie können eine Ausnahme abfangen und eine andere Ausnahme auslösen. In diesem Fall geben Sie die Ausnahme an, die Sie als innere Ausnahme erfasst haben, wie im folgenden Beispiel gezeigt.

catch (InvalidCastException e) 
{
    // Perform some action here, and then throw a new exception.
    throw new YourCustomException("Put your error message here.", e);
}

Sie können eine Ausnahme auch erneut auslösen, wenn eine angegebene Bedingung TRUE ist, wie im folgenden Beispiel gezeigt.

catch (InvalidCastException e)
{
    if (e.Data == null)
    {
        throw;
    }
    else
    {
        // Take some action.
    }
 }

Initialisieren Sie von innerhalb eines try-Blocks nur darin deklarierte Variablen. Andernfalls kann eine Ausnahme auftreten, bevor die Ausführung des Blocks abgeschlossen ist. Im folgenden Codebeispiel wird beispielsweise die Variable n innerhalb des try-Blocks initialisiert. Beim Versuch, diese Variable außerhalb des try-Blocks in der Write(n)-Anweisung zu verwenden, wird ein Compilerfehler generiert.

static void Main() 
{
    int n;
    try 
    {
        // Do not initialize this variable here.
        n = 123;
    }
    catch
    {
    }
    // Error: Use of unassigned local variable 'n'.
    Console.Write(n);
}

Weitere Informationen über catch-Klauseln finden Sie unter try-catch-finally.

Ausnahmen in Async-Methoden

Eine asynchrone Methode wird durch einen async-Modifizierer markiert und gewöhnlich eine oder mehrere erwarten Ausdrücke oder - Anweisungen enthält. Ein Erwartungsausdruck wendet den Sie erwarten-Operator zu Task oder zu Task. Ein await Ausdruck kann nicht in einem catch-Block oder einem - Block finally auftreten.

Wenn await-Steuerelement in der asynchrone Methode erreicht, wird Status in der Methode angehalten, bis die erwartete Aufgabe ausführt. Wenn die Aufgabe abgeschlossen ist, kann die Ausführung in der Methode fortsetzen. Weitere Informationen finden Sie unter Asynchrone Programmierung mit Async und Await (C# und Visual Basic) und Ablaufsteuerung in asynchronen Programmen (C# und Visual Basic).

Die abgeschlossene Aufgabe, zu der await angewendet wird, kann sich in einem Zustand "Faulted" aufgrund eines Ausnahme in der Methode, die die Aufgabe zurückgibt. Die Aufgabe erwartet, löst eine Ausnahme aus. Eine Aufgabe kann in einem den Zustand auch oben beenden, wenn der asynchrone Prozess den gibt es abgebrochen wird. Eine abgebrochene Aufgabe erwartet, löst OperationCanceledException aus. Weitere Informationen dazu, wie Sie einen asynchronen Prozess, finden Sie unter Feinabstimmung der Async-Anwendung (C# und Visual Basic) abbricht.

Um die Ausnahme abfangen, die Aufgabe in einem try-Block erwarten, und die Ausnahme im zugeordneten catch-Block abfangen. Ein Beispiel finden Sie im Beispielabschnitt.

Eine Aufgabe kann in einem "Faulted" Zustand befinden, da mehrere Ausnahmen in der erwarteten asynchrone Methode aufgetreten sind. Beispielsweise könnte die Aufgabe das Ergebnis eines Aufrufs zu Task.WhenAll. Wenn Sie eine solche Aufgabe erwarten, nur eine der Ausnahmen abgefangen wird und Sie können nicht vorhergesagt werden, welche Ausnahme abgefangen wird. Ein Beispiel finden Sie im Beispielabschnitt.

Beispiel

Im folgenden Beispiel enthält der try-Block einen Aufruf der ProcessString-Methode, der möglicherweise eine Ausnahme verursacht. Die catch-Klausel enthält den Ausnahmehandler, der lediglich eine Meldung auf dem Bildschirm anzeigt. Wenn die throw-Anweisung aus MyMethod heraus aufgerufen wird, sucht das System nach der catch-Anweisung und zeigt die Meldung Exception caught an.

    class TryFinallyTest
{
    static void ProcessString(string s)
    {
        if (s == null)
        {
            throw new ArgumentNullException();
        }
    }

    static void Main()
    {
        string s = null; // For demonstration purposes. 

        try
        {            
            ProcessString(s);
        }

        catch (Exception e)
        {
            Console.WriteLine("{0} Exception caught.", e);
        }
    }
}
    /*
    Output:
    System.ArgumentNullException: Value cannot be null.
       at TryFinallyTest.Main() Exception caught.
     * */

Im folgenden Beispiel werden zwei catch-Blöcke verwendet, und die bestimmtste Ausnahme, die zuerst stammt, wird erfasst.

Um die wenigsten bestimmte Ausnahme abzufangen, können Sie die - Anweisung in ProcessString durch die folgende Anweisung ersetzen: throw new Exception().

Wenn Sie den Wenigbesonderecatch-block zuerst im Beispiel platzieren, wird die folgende Fehlermeldung: A previous catch clause already catches all exceptions of this or a super type ('System.Exception').

class ThrowTest3
{
    static void ProcessString(string s)
    {
        if (s == null)
        {
            throw new ArgumentNullException();
        }
    }

    static void Main()
    {
        try
        {
            string s = null;
            ProcessString(s);
        }
        // Most specific: 
        catch (ArgumentNullException e)
        {
            Console.WriteLine("{0} First exception caught.", e);
        }
        // Least specific: 
        catch (Exception e)
        {
            Console.WriteLine("{0} Second exception caught.", e);
        }
    }
}
/*
 Output:
 System.ArgumentNullException: Value cannot be null.
 at Test.ThrowTest3.ProcessString(String s) ... First exception caught.
*/

Das folgende Beispiel veranschaulicht die Ausnahmebehandlung für asynchrone Methoden. Wenn Sie eine Ausnahme abzufangen der löst eine asynchrone Aufgabe, den await Ausdruck in einem try-Block platzieren und fangen die Ausnahme in einem - Block catch ab.

Heben Sie die Auskommentierung throw new Exception Zeile im Beispiel, um Ausnahmebehandlung zu veranschaulichen. Die IsFaulted-Eigenschaft der Aufgabe wird zu True festgelegt, wird die Exception.InnerException-Eigenschaft der Aufgabe zur Ausnahme festgelegt, und die Ausnahme wird im catch-Block abgefangen.

Heben Sie die Auskommentierung der Zeile auf throw new OperationCancelledException, um zu veranschaulichen, wie wenn Sie cancelan asynchroner Prozess wird. Die IsCanceled-Eigenschaft der Aufgabe wird zu true festgelegt, und die Ausnahme wird im catch-Block abgefangen. unter verschiedenen Bedingungen, die nicht auf dieses Beispiel anwenden, wird die IsFaulted-Eigenschaft der Aufgabe zu true festgelegt und IsCanceled wird zu false festgelegt.

        public async Task DoSomethingAsync()
        {
            Task<string> theTask = DelayAsync();

            try
            {
                string result = await theTask;
                Debug.WriteLine("Result: " + result);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Exception Message: " + ex.Message);
            }
            Debug.WriteLine("Task IsCanceled: " + theTask.IsCanceled);
            Debug.WriteLine("Task IsFaulted:  " + theTask.IsFaulted);
            if (theTask.Exception != null)
            {
                Debug.WriteLine("Task Exception Message: "
                    + theTask.Exception.Message);
                Debug.WriteLine("Task Inner Exception Message: "
                    + theTask.Exception.InnerException.Message);
            }
        }

        private async Task<string> DelayAsync()
        {
            await Task.Delay(100);

            // Uncomment each of the following lines to 
            // demonstrate exception handling. 

            //throw new OperationCanceledException("canceled");
            //throw new Exception("Something happened.");
            return "Done";
        }

        // Output when no exception is thrown in the awaited method: 
        //   Result: Done 
        //   Task IsCanceled: False 
        //   Task IsFaulted:  False 

        // Output when an Exception is thrown in the awaited method: 
        //   Exception Message: Something happened. 
        //   Task IsCanceled: False 
        //   Task IsFaulted:  True 
        //   Task Exception Message: One or more errors occurred. 
        //   Task Inner Exception Message: Something happened. 

        // Output when a OperationCanceledException or TaskCanceledException 
        // is thrown in the awaited method: 
        //   Exception Message: canceled 
        //   Task IsCanceled: True 
        //   Task IsFaulted:  False

Das folgende Beispiel veranschaulicht die Ausnahmebehandlung, in der mehrere Aufgaben mehrere Ausnahmen führen können. Der try-Block erwartet die Aufgabe, die durch einen Aufruf Task.WhenAll zurückgegeben wird. Die Aufgabe ist abgeschlossen, wenn die drei Aufgaben, mit denen WhenAll angewendet wird, abgeschlossen sind.

Jede der drei Aufgabenursachen eine Ausnahme. Der catch-Block durchläuft die Ausnahmen durch, die in der Exception.InnerExceptions-Eigenschaft der Aufgabe gefunden werden, die von Task.WhenAll zurückgegeben wurde.

public async Task DoMultipleAsync()
{
    Task theTask1 = ExcAsync(info: "First Task");
    Task theTask2 = ExcAsync(info: "Second Task");
    Task theTask3 = ExcAsync(info: "Third Task");

    Task allTasks = Task.WhenAll(theTask1, theTask2, theTask3);

    try
    {
        await allTasks;
    }
    catch (Exception ex)
    {
        Debug.WriteLine("Exception: " + ex.Message);
        Debug.WriteLine("Task IsFaulted: " + allTasks.IsFaulted);
        foreach (var inEx in allTasks.Exception.InnerExceptions)
        {
            Debug.WriteLine("Task Inner Exception: " + inEx.Message);
        }
    }
}

private async Task ExcAsync(string info)
{
    await Task.Delay(100);

    throw new Exception("Error-" + info);
}

// Output: 
//   Exception: Error-First Task 
//   Task IsFaulted: True 
//   Task Inner Exception: Error-First Task 
//   Task Inner Exception: Error-Second Task 
//   Task Inner Exception: Error-Third Task

C#-Programmiersprachenspezifikation

Weitere Informationen erhalten Sie unter C#-Sprachspezifikation. Die Sprachspezifikation ist die verbindliche Quelle für die Syntax und Verwendung von C#.

Siehe auch

Aufgaben

Gewusst wie: Explizites Auslösen von Ausnahmen

Referenz

C#-Schlüsselwörter

try-, throw- und catch-Anweisungen (C++)

Ausnahmebehandlungsanweisungen (C#-Referenz)

throw (C#-Referenz)

try-finally (C#-Referenz)

Konzepte

C#-Programmierhandbuch

Weitere Ressourcen

C#-Referenz