Normalerweise stimme ich den meisten Warnungen zur Codeanalyse zu und versuche, diese einzuhalten. Allerdings fällt es mir hier schwerer:
CA1031: Allgemeine Ausnahmetypen nicht abfangen
Ich verstehe die Gründe für diese Regel. Aber wenn ich in der Praxis unabhängig von der ausgelösten Ausnahme die gleiche Aktion ausführen möchte, warum sollte ich dann jede einzelne speziell behandeln? Was passiert, wenn sich der von mir aufgerufene Code ändert, um in Zukunft eine neue Ausnahme auszulösen, wenn ich bestimmte Ausnahmen behandle? Jetzt muss ich meinen Code ändern, um diese neue Ausnahme zu behandeln. Wenn ich Exception
meinen Code einfach fange , muss er sich nicht ändern.
Wenn Foo beispielsweise Bar aufruft und Foo die Verarbeitung unabhängig von der Art der von Bar ausgelösten Ausnahmebedingung beenden muss, hat es dann einen Vorteil, die Art der Ausnahmebedingung zu bestimmen, die ich abfange?
Vielleicht ein besseres Beispiel:
public void Foo()
{
// Some logic here.
LogUtility.Log("some message");
}
public static void Log()
{
try
{
// Actual logging here.
}
catch (Exception ex)
{
// Eat it. Logging failures shouldn't stop us from processing.
}
}
Wenn Sie hier keine allgemeine Ausnahme abfangen, müssen Sie alle möglichen Arten von Ausnahmen abfangen. Patrick hat einen guten Punkt, der OutOfMemoryException
nicht auf diese Weise behandelt werden sollte. Was ist, wenn ich jede Ausnahme ignorieren möchte OutOfMemoryException
?
quelle
OutOfMemoryException
? Gleicher Code wie alles andere?OutOfMemoryError
, die ausException
diesem Grund von der Erbschaft Baum getrennt istAntworten:
Diese Regeln sind im Allgemeinen eine gute Idee und sollten daher befolgt werden.
Denken Sie jedoch daran, dass dies allgemeine Regeln sind. Sie decken nicht alle Situationen ab. Sie decken die häufigsten Situationen ab. Wenn Sie eine bestimmte Situation haben und argumentieren können, dass Ihre Technik besser ist (und Sie in der Lage sein sollten, einen Kommentar in den Code zu schreiben, um Ihr Argument dafür zu artikulieren), tun Sie dies (und lassen Sie es dann einer Peer-Review unterziehen).
Auf der Gegenseite des Arguments.
Ich sehe Ihr Beispiel oben nicht als eine gute Situation dafür. Wenn das Protokollierungssystem ausfällt (vermutlich eine andere Ausnahme), möchte ich wahrscheinlich nicht, dass die Anwendung fortgesetzt wird. Beenden und drucken Sie die Ausnahme in der Ausgabe, damit der Benutzer sehen kann, was passiert ist.
quelle
Ja, allgemeine Ausnahmen zu erwischen ist eine schlechte Sache. Eine Ausnahme bedeutet normalerweise, dass das Programm nicht das tun kann, was Sie von ihm verlangt haben.
Es gibt ein paar Arten von Ausnahmen , die Sie könnten handhaben :
Oh, und in der Regel: Wenn Sie nicht wissen, was Sie mit einer Ausnahme tun sollen, wenn Sie sie abfangen, ist es besser, einfach schnell zu scheitern (übergeben Sie die Ausnahme an den Anrufer und lassen Sie ihn damit umgehen)
quelle
Die oberste äußere Schleife sollte eine davon haben, um alles zu drucken, was sie kann, und dann einen schrecklichen, gewalttätigen und lauten Tod sterben (da dies nicht passieren sollte und jemand hören muss).
Andernfalls sollten Sie im Allgemeinen sehr vorsichtig sein, da Sie höchstwahrscheinlich nicht mit allem gerechnet haben, was an diesem Ort passieren könnte, und daher höchstwahrscheinlich nicht richtig damit umgehen werden. Sei so genau wie möglich, damit du nur diejenigen fängst, von denen du weißt, dass sie passieren werden, und lass diejenigen, die du nicht gesehen hast , bis zum oben erwähnten lauten Tod hochsprudeln.
quelle
Es ist nicht so, dass es schlecht ist, es ist nur so, dass bestimmte Fänge besser sind. Wenn Sie spezifisch sind, bedeutet dies, dass Sie konkreter verstehen, was Ihre Anwendung tut, und mehr Kontrolle darüber haben. Im Allgemeinen, wenn Sie auf eine Situation stoßen, in der Sie nur eine Ausnahme abfangen, diese protokollieren und fortfahren, gibt es wahrscheinlich einige schlechte Dinge, die sowieso vor sich gehen. Wenn Sie speziell die Ausnahmen abfangen, von denen Sie wissen, dass sie ein Codeblock oder eine Codemethode auslösen kann, ist die Wahrscheinlichkeit höher, dass Sie sie tatsächlich wiederherstellen können, anstatt nur zu protokollieren und auf das Beste zu hoffen.
quelle
Die beiden Möglichkeiten schließen sich nicht aus.
In einer idealen Situation würden Sie alle möglichen Arten von Ausnahmen abfangen, die Ihre Methode generieren könnte, diese auf Ausnahmebasis behandeln und am Ende eine allgemeine
catch
Klausel hinzufügen , um zukünftige oder unbekannte Ausnahmen abzufangen. Auf diese Weise erhalten Sie das Beste aus beiden Welten.Denken Sie daran, dass Sie die genaueren Ausnahmen zuerst eingeben müssen, um sie zu erfassen.
Bearbeiten: Aus Gründen, die in den Kommentaren angegeben sind, wurde im letzten Fang ein erneuter Wurf hinzugefügt.
quelle
Ich habe das gleiche kürzlich erwogen, und meine vorläufige Schlussfolgerung ist, dass die bloße Frage entsteht, weil die .NET-Ausnahmehierarchie stark durcheinander ist.
Nehmen wir zum Beispiel den Lowly,
ArgumentNullException
der möglicherweise ein vernünftiger Kandidat für eine Ausnahme ist, die Sie nicht abfangen möchten, da er eher auf einen Fehler im Code als auf einen legitimen Laufzeitfehler hinweist. Ah ja. Abgesehen davonNullReferenceException
, dassNullReferenceException
diesSystemException
direkt erfolgt, gibt es keinen Bereich, in den Sie alle "logischen Fehler" einfügen können, um zu fangen (oder nicht zu fangen).Dann gibt es den großen IMNSHO- Pfusch,Wenn Sie ein erhaltenSEHException
Ableiten (viaExternalException
) zu habenSystemException
und es so zu einem "normalen" zu machen.SystemException
SEHException
, möchten Sie einen Dump schreiben und so schnell wie möglich beenden - und mit .NET 4 beginnen, zumindest einige SEH-Ausnahmen gelten als Ausnahmen für beschädigte Zustände , die nicht erfasst werden. Eine gute Sache und eine Tatsache, die dieCA1031
Regel noch nutzloser macht, denn jetzt wird Ihr Faulercatch (Exception)
diese schlimmsten Typen sowieso nicht fangen.Dann scheint es, dass das andere Framework-Zeug entweder
Exception
direkt oder über etwas inkonsistent abgeleitet wirdSystemException
, was jeden Versuch unternimmt, Catch-Klauseln nach so etwas wie Severity Moot zu gruppieren.Es gibt ein Stück von Herrn Lippert mit dem
C#
Titel Vexing Exception , in dem er eine nützliche Kategorisierung von Ausnahmen vorstellt : Sie könnten argumentieren, dass Sie nur "exogene" abfangen möchten, außer ...C#
der Sprache und dem Design von .NET Rahmenausnahmen machen es unmöglich, "nur exogene zu fangen". (und beispielsweise einOutOfMemoryException
möglicherweise sehr gut ein ganz normaler behebbarer Fehler für eine API, die Puffer zuzuweisen hat , die irgendwie groß sind)Fazit für mich ist, dass die Art
C#
und WeiseCA1031
, wie Catch-Blöcke funktionieren und wie die Framework-Ausnahmehierarchie entworfen ist, Regel jenseits von total nutzlos ist . Es gibt vor , bei der Grundfrage zu helfen: "Keine Ausnahmen verschlucken", aber das Verschlucken von Ausnahmen hat nichts mit dem zu tun, was Sie abfangen, sondern mit dem, was Sie dann tun:Es gibt mindestens vier Möglichkeiten , um mit einem Fang legitim umzugehen
Exception
, und esCA1031
scheint , als würde nur eine davon oberflächlich behandelt (nämlich der Fall des erneuten Werfens).Als Randnotiz gibt es eine C # 6-Funktion namens Ausnahmefilter , die die
CA1031
Gültigkeit wieder etwas erhöht , da Sie in der Lage sind, die Ausnahmen, die Sie abfangen möchten, richtig und richtig zu filtern, und es gibt weniger Gründe, ungefiltert zu schreibencatch (Exception)
.quelle
OutOfMemoryException
ist, dass es keinen netten Weg gibt, wie Code sicher sein kann, dass er "nur" den Fehler einer bestimmten Zuordnung anzeigt, für die ein Fehler vorbereitet wurde. Es ist möglich, dass eine andere schwerwiegendere Ausnahme ausgelöst wurde undOutOfMemoryException
während des Abwickelns des Stapels von dieser anderen Ausnahme ein aufgetreten ist. Java mag mit seinen "try-with-resources" -Versuchen zu spät zu der Party gekommen sein, aber es behandelt Ausnahmen während des Abwickelns des Stacks ein bisschen besser als .NET.finally
Blöcke vor Ausnahmen schützen , von denen man realistisch erwarten kann, dass sie so auftreten, dass sowohl die ursprünglichen als auch die neuen Ausnahmen protokolliert werden. Leider erfordert dies häufig eine Speicherzuweisung, die zu eigenen Fehlern führen kann.Pokemon Ausnahmebehandlung (ich muss sie alle fangen!) Ist sicherlich nicht immer schlecht. Wenn Sie eine Methode einem Client, insbesondere einem Endbenutzer, zur Verfügung stellen, ist es häufig besser, alles und jeden zu erfassen, als Ihre Anwendung zum Absturz zu bringen und zu brennen.
Im Allgemeinen sollten sie jedoch vermieden werden, wo Sie können. Sofern Sie keine spezifischen Maßnahmen basierend auf dem Typ der Ausnahme ergreifen können, ist es besser, sie nicht zu behandeln und zuzulassen, dass die Ausnahme in die Luft sprudelt, anstatt die Ausnahme zu verschlucken oder sie falsch zu behandeln.
Schauen Sie sich diese SO-Antwort an, um mehr darüber zu lesen.
quelle
LoadDocument()
ist es im Grunde unmöglich, alle Fehler zu identifizieren, aber 99% der Ausnahmen, die ausgelöst werden könnten, bedeuten einfach "Es war nicht möglich, den Inhalt einer Datei mit dem angegebenen Namen als zu interpretieren ein Dokument, damit umgehen. " Wenn jemand versucht, etwas zu öffnen, das keine gültige Dokumentdatei ist, sollte dies die Anwendung nicht zum Absturz bringen und keine anderen geöffneten Dokumente löschen. Pokemon Fehlerbehandlung in solchen Fällen ist hässlich, aber ich kenne keine guten Alternativen.Das Abfangen einer allgemeinen Ausnahme ist schlecht, da Ihr Programm dadurch in einem undefinierten Zustand bleibt. Sie wissen nicht, wo etwas schief gelaufen ist, und wissen nicht, was Ihr Programm tatsächlich getan hat oder nicht getan hat.
Wenn ich ein Programm schließe, kann ich alles abfangen. Solange Sie es in Ordnung aufräumen können. Nichts ist so ärgerlich wie ein Programm, das Sie schließen, und das nur einen Fehlerdialog auslöst, der nichts anderes tut, als dort zu sitzen, nicht zu verschwinden und den Computer daran zu hindern, herunterzufahren.
In einer verteilten Umgebung kann Ihre Protokollmethode nach hinten losgehen: Wenn Sie eine allgemeine Ausnahme abfangen, kann dies bedeuten, dass Ihr Programm die Protokolldatei weiterhin sperrt und andere Benutzer daran hindert, Protokolle zu erstellen.
quelle
Wie andere gesagt haben, ist es wirklich schwierig (wenn nicht unmöglich), sich eine Aktion vorzustellen, die Sie unabhängig von der ausgelösten Ausnahme ausführen möchten. Nur ein Beispiel sind Situationen, in denen der Status des Programms beschädigt wurde und jede weitere Verarbeitung zu Problemen führen kann (dies ist der Grund dafür
Environment.FailFast
).Für Hobby-Code ist es in Ordnung, ihn zu fangen
Exception
, aber für professionellen Code, der einen neuen Ausnahmetyp einführt, sollte er mit dem gleichen Respekt behandelt werden wie eine Änderung der Methodensignatur, dh, er gilt als brechende Änderung. Wenn Sie diesen Standpunkt abonnieren, ist es sofort offensichtlich, dass das Ändern (oder Überprüfen) des Client-Codes die einzig richtige Vorgehensweise ist.Sicher, denn Sie werden nicht nur Ausnahmen abfangen, die von Ihnen geworfen werden
Bar
. Es wird auch Ausnahmen geben, die die Clients von Bar oder sogar die Laufzeit während der ZeitBar
auf dem Aufrufstapel auslösen können. Ein gut geschriebenerBar
Benutzer sollte bei Bedarf einen eigenen Ausnahmetyp definieren, damit der Aufrufer die von ihm selbst ausgegebenen Ausnahmen gezielt abfangen kann.IMHO ist dies der falsche Weg, um über die Ausnahmebehandlung nachzudenken. Sie sollten mit Whitelists arbeiten (Ausnahmetypen A und B abfangen), nicht mit Blacklists (alle Ausnahmen mit Ausnahme von X abfangen).
quelle
Vielleicht . Es gibt Ausnahmen zu jeder Regel und keine Regel sollte unkritisch befolgt werden. Ihr Beispiel könnte möglicherweise einer der Fälle sein, in denen es sinnvoll ist, alle Ausnahmen zu verschlucken. Zum Beispiel, wenn Sie einem kritischen Produktionssystem eine Ablaufverfolgung hinzufügen und absolut sicher sein möchten, dass Ihre Änderungen die Hauptaufgabe der App nicht stören.
Allerdings sollten Sie sorgfältig über mögliche Gründe für das Scheitern denken , bevor Sie sich entscheiden, still , sie alle zu ignorieren. Was ist zum Beispiel, wenn der Grund für die Ausnahme ist:
Möchten Sie nicht sofort benachrichtigt werden, dass dieses Problem vorliegt, damit Sie es beheben können? Das Verschlucken der Ausnahme bedeutet, dass Sie nie wissen, dass etwas schief gelaufen ist.
Einige Probleme (z. B. der Datenträger ist voll) können auch dazu führen, dass andere Teile der Anwendung fehlschlagen. Dieser Fehler wird jedoch jetzt nicht protokolliert, sodass Sie es nie erfahren.
quelle
Ich möchte dies eher aus einer logischen als aus einer technischen Perspektive heraus ansprechen.
Nun, jemand würde damit umgehen müssen. Das ist die Idee. Bei der Erstellung von Bibliothekscodes ist es jedoch ratsam, neue Ausnahmetypen hinzuzufügen, da dies wahrscheinlich zum Absturz von Clients führt. Dies sollte jedoch nicht häufig vorkommen.
Ihre Frage lautet im Grunde: "Was ist, wenn es mich nicht interessiert, was schief gelaufen ist? Muss ich wirklich die Mühe machen, herauszufinden, was es war?"
Hier ist der Beauty-Teil: Nein, tust du nicht.
"Also, kann ich einfach wegschauen und alles, was böse auftaucht, automatisch unter den Teppich kehren lassen und damit fertig sein?"
Nein, so funktioniert es auch nicht.
Der Punkt ist, die Sammlung möglicher Ausnahmen ist immer größer als die Sammlung, die Sie erwarten, und interessiert sich für den Kontext Ihres lokalen kleinen Problems. Sie behandeln die, die Sie erwarten, und wenn etwas Unerwartetes passiert, überlassen Sie es den übergeordneten Bearbeitern, anstatt es zu verschlucken. Wenn Sie sich nicht für eine Ausnahme interessieren, die Sie nicht erwartet haben, setzen Sie auf jemanden, der den Call-Stack aktiviert, und es wäre Sabotage, eine Ausnahme zu beenden, bevor sie ihren Handler erreicht.
"Aber ... aber ... dann könnte eine dieser anderen Ausnahmen, die mir egal sind, dazu führen, dass meine Aufgabe fehlschlägt!"
Ja. Aber sie werden immer wichtiger als die lokal gehandhabten. Wie ein Feueralarm oder der Chef, der dir sagt, du sollst aufhören, was du tust, und eine dringendere Aufgabe übernehmen, die auftaucht.
quelle
Sie sollten allgemeine Ausnahmen auf der obersten Ebene jedes Prozesses abfangen und diese behandeln, indem Sie den Fehler so gut wie möglich melden und dann den Prozess beenden.
Sie sollten keine allgemeinen Ausnahmen abfangen und versuchen, die Ausführung fortzusetzen.
quelle