2612 Stimmen

Mehrere Ausnahmen auf einmal abfangen?

Es wird davon abgeraten, einfach zu fangen System.Exception . Stattdessen sollten nur die "bekannten" Ausnahmen abgefangen werden.

Dies führt manchmal zu unnötigem, sich wiederholendem Code, zum Beispiel:

try
{
    WebId = new Guid(queryString["web"]);
}
catch (FormatException)
{
    WebId = Guid.Empty;
}
catch (OverflowException)
{
    WebId = Guid.Empty;
}

Ich frage mich: Gibt es eine Möglichkeit, beide Ausnahmen abzufangen und nur die WebId = Guid.Empty einmal anrufen?

Das angegebene Beispiel ist recht einfach, da es sich nur um eine GUID . Stellen Sie sich aber einen Code vor, bei dem Sie ein Objekt mehrfach ändern, und wenn eine der Manipulationen erwartungsgemäß fehlschlägt, möchten Sie die "Rückstellung" der object . Wenn jedoch eine unerwartete Ausnahme auftritt, möchte ich diese trotzdem höher setzen.

8 Stimmen

Wenn Sie .net 4 und höher verwenden, bevorzuge ich die Verwendung von Aggregateexception msdn.microsoft.com/de-us/library/system.aggregateexception.aspx

2 Stimmen

Bepenfriends- Seit System.Guid wirft nicht AggregateException Es wäre toll, wenn Sie (oder jemand) eine Antwort posten könnte, die zeigt, wie Sie es in eine AggregateException usw. einpacken würden.

1 Stimmen

Zur Verwendung AggregateException : Auslösen einer AggregateException in meinem eigenen Code

149voto

Athari Punkte 32497

Der Vollständigkeit halber sei erwähnt, dass .NET 4.0 kann der Code wie folgt umgeschrieben werden:

Guid.TryParse(queryString["web"], out WebId);

TryParse löst nie Ausnahmen aus und gibt false zurück, wenn das Format falsch ist, und setzt WebId auf Guid.Empty .


Desde C# 7 können Sie vermeiden, eine Variable in einer separaten Zeile einzuführen:

Guid.TryParse(queryString["web"], out Guid webId);

Sie können auch Methoden zum Parsen von zurückgegebenen Tupeln erstellen, die in .NET Framework ab Version 4.6 noch nicht verfügbar sind:

(bool success, Guid result) TryParseGuid(string input) =>
    (Guid.TryParse(input, out Guid result), result);

Und verwenden Sie sie so:

WebId = TryParseGuid(queryString["web"]).result;
// or
var tuple = TryParseGuid(queryString["web"]);
WebId = tuple.success ? tuple.result : DefaultWebId;

Das nächste nutzlose Update zu dieser nutzlosen Antwort kommt, wenn die Dekonstruktion von Out-Parametern in C# 12 implementiert ist :)

101voto

Maniero Punkte 9141

Wenn Sie Ihre Anwendung auf C# 6 aktualisieren können, haben Sie Glück. Die neue C#-Version hat Exception-Filter implementiert. So können Sie dies schreiben:

catch (Exception ex) when (ex is FormatException || ex is OverflowException) {
    WebId = Guid.Empty;
}

Manche Leute denken, dieser Code sei dasselbe wie

catch (Exception ex) {                
    if (ex is FormatException || ex is OverflowException) {
        WebId = Guid.Empty;
    }
    throw;
}

Ist es aber nicht. Tatsächlich ist dies die einzige neue Funktion in C# 6, die in früheren Versionen nicht emuliert werden kann. Erstens bedeutet ein Re-Throw mehr Overhead als das Überspringen des Catches. Zweitens ist es semantisch nicht gleichwertig. Die neue Funktion erhält den Stack intakt, wenn Sie Ihren Code debuggen. Ohne diese Funktion ist der Crash Dump weniger nützlich oder sogar nutzlos.

Siehe eine Diskussion zu diesem Thema auf CodePlex Nicht mehr verfügbar. Und eine Beispiel für den Unterschied .

14 Stimmen

Werfen ohne Ausnahme bewahrt den Stapel, aber "throw ex" überschreibt ihn.

89voto

Nechemia Hoffmann Punkte 1426

Aktualisierung für C# 9

Die Verwendung des neue Verbesserungen bei der Mustererkennung in C# 9 können Sie den Ausdruck im Ausnahmefilter verkürzen. Nun, fangen mehrere Ausnahmen ist eine einfache ist dies:

try
{
    WebId = new Guid(queryString["web"]);
}
catch (Exception e) when (e is FormatException or OverflowException)
{
    WebId = Guid.Empty;
}

62voto

Fabian Punkte 865

Mit C# 7 die Antwort von Michael Stum kann verbessert werden, ohne dass die Lesbarkeit einer switch-Anweisung beeinträchtigt wird:

catch (Exception ex)
{
    switch (ex)
    {
        case FormatException _:
        case OverflowException _:
            WebId = Guid.Empty;
            break;
        default:
            throw;
    }
}

Dank an Orace Kommentar kann dies mit C# 8 vereinfacht werden, indem die Variable discard weggelassen wird:

catch (Exception ex)
{
    switch (ex)
    {
        case FormatException:
        case OverflowException:
            WebId = Guid.Empty;
            break;
        default:
            throw;
    }
} 

Und mit C# 8 als Schalterausdruck:

catch (Exception ex)
{
    WebId = ex switch
    {
        _ when ex is FormatException || ex is OverflowException => Guid.Empty,
        _ => throw ex
    };
}

Als Nechemia Hoffmann hervorgehoben. Das letzte Beispiel führt zum Verlust des Stacktrace. Dies kann durch die Verwendung der Erweiterungsmethode verhindert werden, die in Jürgen Steinblock um den Stacktrace vor dem Auslösen zu erfassen:

catch (Exception ex)
{
    WebId = ex switch
    {
        _ when ex is FormatException || ex is OverflowException => Guid.Empty,
        _ => throw ex.Capture()
    };
}

public static Exception Capture(this Exception ex)
{
    ExceptionDispatchInfo.Capture(ex).Throw();
    return ex;
}

Beide Arten können mit den Verbesserungen des Mustervergleichs in C# 9 vereinfacht werden:

catch (Exception ex)
{
    switch (ex)
    {
        case FormatException or OverflowException:
            WebId = Guid.Empty;
            break;
        default:
            throw;
    }
} 

catch (Exception ex)
{
    WebId = ex switch
    {
        _ when ex is FormatException or OverflowException => Guid.Empty,
        _ => throw ex.Capture()
    };
}

0 Stimmen

Verlieren Sie nicht den Stacktrace, wenn Sie throw ex ?

0 Stimmen

Ja, im Beispiel des Schalterausdrucks (2. Beispiel) verlieren Sie die Stacktrace. Danke für den Hinweis. (Nur um das klarzustellen: im ersten Beispiel geht sie nicht verloren)

0 Stimmen

Für den ersten Codeblock, _ werden in C#8 nicht mehr benötigt

49voto

Konstantin Spirin Punkte 19144
catch (Exception ex) when (ex is FormatException or OverflowException)
{
    WebId = Guid.Empty;
}

oder

catch (Exception ex)
{
    if (ex is not FormatException and not OverflowException)
        throw;

    WebId = Guid.Empty;
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X