2559 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

2444voto

Joseph Daigle Punkte 46087

Fangen System.Exception und schalten Sie die Typen

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

    throw;
}

31 Stimmen

Obligatorische Erinnerung an die Redakteure, die nicht OP sind: Das Bearbeiten neuer Antworten für Updates ist etwas, für das wir einen Ablehnungsgrund haben, und >2k Benutzer sind davon nicht ausgenommen. Aktualisieren Sie nicht die Antworten anderer Leute, um Aktualisierungen auf Standardversionen oder andere Versionen der Technik, die für beliebige Antworten gilt, wiederzugeben - schreiben Sie stattdessen eine neue Antwort (Pro-Tipp; das bringt Ihnen mehr Ansehen). Wenn es zusätzlich extreme Einwände gegen die Antwort gibt, hinterlässt du einen Kommentar, in dem du das Problem erklärst, und verlinkst auf die Antwort, die jetzt besser anwendbar ist. (Und stimmen Sie über die Antwort ab, wie Sie möchten)

865voto

Craig Tullis Punkte 9029

EDIT: Ich stimme mit anderen, die sagen, dass ab C# 6.0, Ausnahme-Filter sind jetzt eine völlig gute Möglichkeit zu gehen: catch (Exception ex) when (ex is ... || ex is ... )

Allerdings hasse ich immer noch das einzeilige Layout und würde persönlich den Code wie folgt gestalten. Ich denke, dass dies sowohl funktional als auch ästhetisch ist, da ich glaube, dass es die Verständlichkeit verbessert. Manche mögen anderer Meinung sein:

catch (Exception ex) when (
    ex is ...
    || ex is ...
    || ex is ...
)

ORIGINAL:

Ich weiß, ich bin ein wenig zu spät zur Party hier, aber heiliger Bimbam...

Um es gleich auf den Punkt zu bringen, dies ist eine Art Duplikat einer früheren Antwort, aber wenn Sie wirklich eine gemeinsame Aktion für mehrere Ausnahmetypen durchführen möchten und die ganze Sache sauber und ordentlich innerhalb des Anwendungsbereichs der einen Methode halten, warum nicht einfach eine Lambda/Schließung/Inline-Funktion verwenden, um etwas wie das Folgende zu tun? Ich meine, die Chancen stehen gut, dass Sie am Ende feststellen, dass Sie diese Schließung zu einer separaten Methode machen wollen, die Sie überall verwenden können. Aber dann wird es super einfach sein, das zu tun, ohne den Rest des Codes strukturell zu verändern. Oder?

private void TestMethod ()
{
    Action<Exception> errorHandler = ( ex ) => {
        // write to a log, whatever...
    };

    try
    {
        // try some stuff
    }
    catch ( FormatException  ex ) { errorHandler ( ex ); }
    catch ( OverflowException ex ) { errorHandler ( ex ); }
    catch ( ArgumentNullException ex ) { errorHandler ( ex ); }
}

Ich kann nicht umhin, mich zu fragen ( Warnung: ein wenig Ironie/Sarkasmus voraus), warum um alles in der Welt sollte man sich diese Mühe machen, um im Grunde nur Folgendes zu ersetzen:

try
{
    // try some stuff
}
catch( FormatException ex ){}
catch( OverflowException ex ){}
catch( ArgumentNullException ex ){}

...mit einer verrückten Variante dieses nächsten Codegeruchs, ich meine Beispiel, nur um so zu tun, als würden Sie ein paar Tastenanschläge sparen.

// sorta sucks, let's be honest...
try
{
    // try some stuff
}
catch( Exception ex )
{
    if (ex is FormatException ||
        ex is OverflowException ||
        ex is ArgumentNullException)
    {
        // write to a log, whatever...
        return;
    }
    throw;
}

Denn sie ist nicht automatisch besser lesbar.

Zugegeben, ich habe die drei identischen Instanzen von /* write to a log, whatever... */ return; aus dem ersten Beispiel.

Aber darum geht es mir ja auch. Ihr habt doch alle schon von Funktionen/Methoden gehört, oder? Ganz im Ernst. Schreiben Sie eine gemeinsame ErrorHandler Funktion und rufen sie z.B. von jedem Catch-Block aus auf.

Wenn Sie mich fragen, ist das zweite Beispiel (mit der if et is Schlüsselwörter) ist sowohl deutlich weniger lesbar als auch gleichzeitig deutlich fehleranfälliger in der Wartungsphase Ihres Projekts.

Die Wartungsphase wird für jeden, der relativ neu in der Programmierung ist, 98,7 % oder mehr der gesamten Lebensdauer Ihres Projekts ausmachen, und der arme Trottel, der die Wartung durchführt, wird mit ziemlicher Sicherheit jemand anderes als Sie sein. Und es besteht eine sehr gute Chance, dass er 50% seiner Zeit damit verbringt, Ihren Namen zu verfluchen.

Und natürlich bellt FxCop Sie an und Sie müssen également fügen Sie Ihrem Code ein Attribut hinzu, das mit dem laufenden Programm nichts zu tun hat und nur dazu dient, FxCop mitzuteilen, dass es ein Problem ignorieren soll, das es in 99,9 % der Fälle völlig korrekt anzeigt. Und, entschuldigen Sie, vielleicht irre ich mich, aber wird dieses "Ignorieren"-Attribut nicht am Ende tatsächlich in Ihre Anwendung kompiliert?

Wäre es sinnvoll, die gesamte if Test in einer Zeile die Lesbarkeit verbessern? Nein, das glaube ich nicht. Ich meine, ein anderer Programmierer hat vor langer Zeit einmal vehement behauptet, dass mehr Code in einer Zeile dazu führt, dass er "schneller läuft". Aber natürlich war er völlig verrückt. Der Versuch, ihm zu erklären, wie der Interpreter oder Compiler diese lange Zeile in einzelne Anweisungen pro Zeile zerlegen würde - im Wesentlichen identisch mit dem Ergebnis, wenn er den Code einfach lesbar gemacht hätte, anstatt zu versuchen, den Compiler zu überlisten - hatte keinerlei Wirkung auf ihn. Aber ich schweife ab.

Wie viel weniger lesbar wird, wenn Sie in ein oder zwei Monaten drei weitere Ausnahmetypen hinzufügen? (Antwort: Es wird ein Los weniger lesbar).

Einer der wichtigsten Punkte ist, dass die Formatierung des textuellen Quellcodes, den wir alle jeden Tag sehen, vor allem dazu dient, anderen Menschen klar zu machen, was tatsächlich passiert, wenn der Code ausgeführt wird. Denn der Compiler verwandelt den Quellcode in etwas völlig anderes und kümmert sich nicht im Geringsten um die Formatierung Ihres Codes. Also ist "Alles-online" auch total scheiße.

Ich sage ja nur...

// super sucks...
catch( Exception ex )
{
    if ( ex is FormatException || ex is OverflowException || ex is ArgumentNullException )
    {
        // write to a log, whatever...
        return;
    }
    throw;
}

14 Stimmen

Sie können die neue Syntax verwenden: when (ex ist FormatException oder OverflowException oder ArgumentNullException)

2 Stimmen

@MorganM., ich bin gelegentlich ein Fan einer neuen Syntax. Dies ist wahrscheinlich einer dieser Fälle :)

0 Stimmen

Ich bin mir ziemlich sicher, dass das Programm schneller läuft, wenn Sie den Wortumbruch auch in Ihrer IDE deaktivieren. Das ist einer dieser versteckten Lebenshilfen für Programmierer!

503voto

Joe Punkte 6668

Wie bereits von anderen erwähnt, können Sie eine if Anweisung in Ihrem Catch-Block, um festzustellen, was los ist. C#6 unterstützt Exception-Filter, so dass die folgenden funktionieren wird:

try { … }
catch (Exception e) when (MyFilter(e))
{
    …
}

Le site MyFilter Methode könnte dann etwa so aussehen:

private bool MyFilter(Exception e)
{
  return e is ArgumentNullException || e is FormatException;
}

Alternativ kann dies auch inline geschehen (die rechte Seite der when-Anweisung muss nur ein boolescher Ausdruck sein).

try { … }
catch (Exception e) when (e is ArgumentNullException || e is FormatException)
{
    …
}

Dies ist anders als die Verwendung eines if Anweisung innerhalb der catch Block, unter Verwendung von Ausnahmefiltern wird nicht den Stapel abwickeln.

Sie können herunterladen Visual Studio 2015 um dies zu überprüfen.

Wenn Sie Visual Studio 2013 weiterhin verwenden möchten, können Sie das folgende Nuget-Paket installieren:

Install-Package Microsoft.Net.Compilers

Zum Zeitpunkt der Erstellung dieses Dokuments wird dies auch Unterstützung für C# 6 beinhalten.

Der Verweis auf dieses Paket führt dazu, dass das Projekt unter Verwendung der spezifischen Version der C#- und Visual Basic-Compiler erstellt wird, die in dem Paket enthaltenen C#- und Visual-Basic-Compilern erstellt wird, im Gegensatz zu einer vom System installierten Version.

0 Stimmen

Sie sind nicht in der Lage, generische Ausnahmelogik zu tun, weil Sie nicht beide Ausnahmen nennen können, die Sie den gleichen Variablennamen abfangen.

206voto

Greg Beech Punkte 127525

Leider nicht in C#, da Sie einen Ausnahmefilter benötigen, um dies zu tun, und C# bietet diese Funktion von MSIL nicht. VB.NET hat diese Fähigkeit jedoch, z.B.

Catch ex As Exception When TypeOf ex Is FormatException OrElse TypeOf ex Is OverflowException

Sie könnten eine anonyme Funktion verwenden, um Ihren Fehlercode zu kapseln, und ihn dann in diesen speziellen Catch-Blöcken aufrufen:

Action onError = () => WebId = Guid.Empty;
try
{
    // something
}
catch (FormatException)
{
    onError();
}
catch (OverflowException)
{
    onError();
}

171voto

Mat J Punkte 5192

Ausnahmefilter sind jetzt in c# 6+ verfügbar. Sie können tun

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

In C# 7.0+ können Sie dies auch mit Mustervergleichen kombinieren

try
{
   await Task.WaitAll(tasks);
}
catch (Exception ex) when( ex is AggregateException ae &&
                           ae.InnerExceptions.Count > tasks.Count/2)
{
   //More than half of the tasks failed maybe..? 
}

4 Stimmen

Diese Methode wird nicht nur bevorzugt, weil sie einfach und klar ist, sondern auch, weil der Stack nicht abgewickelt werden muss, wenn die Bedingungen nicht erfüllt sind, was im Vergleich zu rethrow bessere Leistung und Diagnoseinformationen liefert.

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