Suche…


Bemerkungen

Verbunden:

Eine Ausnahme abfangen

Code kann und sollte in Ausnahmefällen Ausnahmen auslösen. Beispiele hierfür sind:

Der Anrufer kann mit diesen Ausnahmen umgehen, indem er sie "fängt", und sollte dies nur tun, wenn:

  • Sie kann den außergewöhnlichen Umstand tatsächlich lösen oder sich angemessen erholen, oder;
  • Es kann zusätzlichen Kontext für die Ausnahme bereitstellen, der nützlich wäre, wenn die Ausnahme erneut ausgelöst werden muss (erneut geworfene Ausnahmen werden von Ausnahmebehandlern weiter oben im Aufrufstapel abgefangen.)

Es ist zu beachten, dass die Entscheidung, eine Ausnahme nicht abzufangen, vollkommen gültig ist, wenn beabsichtigt ist, auf einer höheren Ebene behandelt zu werden.

Das Abfangen einer Ausnahme erfolgt, indem der potenziell auslösende Code wie folgt in einen try { ... } Block eingeschlossen wird und die Ausnahmen erfasst werden, die in einem catch (ExceptionType) { ... } -Block behandelt werden können:

Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();

Stream fileStream;

try
{
    fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
    Console.WriteLine("File '{0}' could not be found.", filename);
}

Mit einem endgültigen Block

Der finally { ... } -Block eines try-finally oder try-catch-finally wird immer ausgeführt, unabhängig davon, ob eine Ausnahmebedingung aufgetreten ist oder nicht (außer wenn eine StackOverflowException ausgelöst wurde oder ein Aufruf an Environment.FailFast() ).

Es kann verwendet werden, um Ressourcen, die im try { ... } -Block gesichert wurden, sicher freizugeben oder zu bereinigen.

Console.Write("Please enter a filename: ");
string filename = Console.ReadLine();

Stream fileStream = null;

try
{
    fileStream = File.Open(filename);
}
catch (FileNotFoundException)
{
    Console.WriteLine("File '{0}' could not be found.", filename);
}
finally
{
    if (fileStream != null)
    {
        fileStream.Dispose();
    }
}

Gefangene Ausnahmen fangen und erneut werfen

Wenn Sie eine Ausnahme abfangen und etwas tun möchten, die Ausführung des aktuellen Codeblocks jedoch aufgrund der Ausnahme nicht fortsetzen können, möchten Sie möglicherweise die Ausnahme für den nächsten Ausnahmebehandler im Aufrufstapel erneut auslösen. Es gibt gute und schlechte Wege, dies zu tun.

private static void AskTheUltimateQuestion()
{
    try
    {
        var x = 42;
        var y = x / (x - x); // will throw a DivideByZeroException

        // IMPORTANT NOTE: the error in following string format IS intentional
        // and exists to throw an exception to the FormatException catch, below
        Console.WriteLine("The secret to life, the universe, and everything is {1}", y); 
    }
    catch (DivideByZeroException)
    {
        // we do not need a reference to the exception
        Console.WriteLine("Dividing by zero would destroy the universe.");

        // do this to preserve the stack trace:
        throw;
    }
    catch (FormatException ex)
    {
        // only do this if you need to change the type of the Exception to be thrown 
        // and wrap the inner Exception

        // remember that the stack trace of the outer Exception will point to the
        // next line

        // you'll need to examine the InnerException property to get the stack trace
        // to the line that actually started the problem

        throw new InvalidOperationException("Watch your format string indexes.", ex);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Something else horrible happened. The exception: " + ex.Message);

        // do not do this, because the stack trace will be changed to point to
        // this location instead of the location where the exception
        // was originally thrown:
        throw ex; 
    }
}

static void Main()
{
    try
    {
        AskTheUltimateQuestion();
    }
    catch
    {
        // choose this kind of catch if you don't need any information about 
        // the exception that was caught

        // this block "eats" all exceptions instead of rethrowing them
    }
}

Sie können nach Ausnahme-Typ und sogar nach Ausnahme-Eigenschaften filtern (neu in C # 6.0, etwas länger in VB.NET verfügbar (Zitat erforderlich)):

Dokumentation / C # / neue Funktionen

Ausnahmefilter

Seit C # 6.0 können Ausnahmen mit dem Operator when gefiltert werden.

Dies ist vergleichbar mit der Verwendung eines einfachen if , der den Stack jedoch nicht abwickelt, wenn die Bedingung innerhalb des when nicht erfüllt ist.

Beispiel

try
{ 
  // ...
}
catch (Exception e) when (e.InnerException != null) // Any condition can go in here.
{
  // ...
}

Die gleichen Informationen finden Sie in den C # 6.0-Features hier: Ausnahmefilter

Eine Ausnahme innerhalb eines catch-Blocks erneut auslösen

Innerhalb eines catch Blocks kann das throw Schlüsselwort alleine verwendet werden, ohne einen Ausnahmewert anzugeben, um die gerade abgefangene Ausnahme erneut auszulösen . Beim erneuten Auslösen einer Ausnahme kann die ursprüngliche Ausnahme die Ausnahmebehandlungskette fortsetzen, wobei der Aufrufstack oder die zugehörigen Daten erhalten bleiben:

try {...}
catch (Exception ex) {
  // Note: the ex variable is *not* used
  throw;
}

Ein häufiges Anti-Pattern ist das throw ex , was die Ansicht des Stack-Trace des nächsten Exception-Handlers einschränkt:

try {...}
catch (Exception ex) {
  // Note: the ex variable is thrown
  //  future stack traces of the exception will not see prior calls
  throw ex;  
}

Im Allgemeinen ist die Verwendung von throw ex nicht wünschenswert, da zukünftige Ausnahmebehandler, die die Stack-Ablaufverfolgung untersuchen, nur Aufrufe bis zu throw ex . Wenn Sie die ex Variable weglassen und nur das throw Schlüsselwort verwenden, sprudelt die ursprüngliche Ausnahme.

Eine Ausnahme von einer anderen Methode auslösen und dabei die Informationen beibehalten

Gelegentlich möchten Sie eine Ausnahme abfangen und aus einem anderen Thread oder einer anderen Methode werfen, während der ursprüngliche Ausnahmestapel erhalten bleibt. Dies kann mit ExceptionDispatchInfo :

using System.Runtime.ExceptionServices;

void Main()
{
    ExceptionDispatchInfo capturedException = null;
    try
    {
        throw new Exception();
    }
    catch (Exception ex)
    {
        capturedException = ExceptionDispatchInfo.Capture(ex);
    }
    
    Foo(capturedException);
}

void Foo(ExceptionDispatchInfo exceptionDispatchInfo)
{
    // Do stuff

    if (capturedException != null)
    {
        // Exception stack trace will show it was thrown from Main() and not from Foo()
        exceptionDispatchInfo.Throw();
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow