Während ich den Code meines Kollegen selbst von jemandem pflege, der behauptet, ein leitender Entwickler zu sein, sehe ich oft den folgenden Code:
try
{
//do something
}
catch
{
//Do nothing
}
oder manchmal schreiben sie Protokollinformationen in Protokolldateien wie den folgenden try catch
Block
try
{
//do some work
}
catch(Exception exception)
{
WriteException2LogFile(exception);
}
Ich frage mich nur, ob das, was sie getan haben, die beste Praxis ist. Es macht mich verwirrt, weil Benutzer in meinem Denken wissen sollten, was mit dem System passiert.
Bitte geben Sie mir einen Rat.
NullReference
oderArgumentNull
das nicht Teil des Anwendungsflusses ist), bedeutet dies, dass ein Fehler behoben werden muss, sodass die Protokollierung dazu beiträgt, Ihren Code viel schneller zu debuggen.Antworten:
Meine Strategie zur Ausnahmebehandlung lautet:
Um alle unbehandelten Ausnahmen abzufangen, indem Sie sich an die
Application.ThreadException event
anschließen, entscheiden Sie:Dann füge ich immer jeden Code hinzu, der extern ausgeführt wird in
try/catch
:Dann füge ich 'try / catch' bei
ApplicationException("custom message", innerException)
, um zu verfolgen, was wirklich passiert istAußerdem versuche ich mein Bestes, um Ausnahmen richtig zu sortieren . Es gibt Ausnahmen, die:
finally
während eines Füllvorgangs in den Abschnitt einTreeView
).Dem Benutzer ist das egal, aber es ist wichtig zu wissen, was passiert ist. Also logge ich sie immer ein:
Es wird empfohlen, einige statische Methoden zu entwerfen, um Ausnahmen in den Fehlerbehandlungsroutinen der obersten Ebene der Anwendung zu behandeln .
Ich zwinge mich auch zu versuchen:
So endlich :
Schlecht:
Nutzlos:
Endlich einen Versuch ohne Fang zu machen, ist absolut gültig:
Was ich auf höchster Ebene mache:
Was ich in einigen sogenannten Funktionen mache:
Es gibt viel mit der Ausnahmebehandlung (benutzerdefinierte Ausnahmen) zu tun, aber diese Regeln, die ich zu beachten versuche, reichen für die einfachen Anwendungen aus, die ich mache.
Hier ist ein Beispiel für Erweiterungsmethoden, mit denen abgefangene Ausnahmen auf komfortable Weise behandelt werden können. Sie sind so implementiert, dass sie miteinander verkettet werden können, und es ist sehr einfach, eine eigene Verarbeitung abgefangener Ausnahmen hinzuzufügen.
quelle
catch(Exception ex) { throw ex; }
in C # ist schlechter als redundant (unabhängig vom Ausnahmetyp, den Sie abfangen). Verwenden Sie zum erneuten Werfenthrow;
. Bei ersteren sieht die Ausnahme so aus, als stamme sie von Ihrer,throw ex
während sie bei letzteren ordnungsgemäß von der ursprünglichenthrow
Aussage stammt.Application.ThreadException
Ereignis ein und schließen jede Ausnahme mit einem eincatch(Exception ex) {ex.Log(ex);}
. Ich würde wahrscheinlich zustimmen, dass Ersteres eine ausgezeichnete Praxis ist, aber Letzteres erhöht das Risiko, dass Ihre Fehlerprotokolle dupliziert werden, und verbirgt, dass die Ausnahme aufgetreten ist. Ist auchthrow ex
sehr sehr schlecht.Application.ThreadException
Veranstaltung, das war mir nicht bewusst, sehr nützlich.Die beste Vorgehensweise ist, dass die Ausnahmebehandlung niemals Probleme verbergen sollte . Dies bedeutet, dass
try-catch
Blöcke äußerst selten sein sollten.Es gibt 3 Umstände, unter denen die Verwendung von a
try-catch
sinnvoll ist.Gehen Sie immer so tief wie möglich mit bekannten Ausnahmen um. Wenn Sie jedoch eine Ausnahme erwarten, ist es normalerweise besser, diese zuerst zu testen. Zum Beispiel werden Analyse-, Formatierungs- und arithmetische Ausnahmen fast immer besser zuerst durch Logikprüfungen behandelt als durch bestimmte
try-catch
.Wenn Sie für eine Ausnahme etwas tun müssen (z. B. Protokollierung oder Rollback einer Transaktion), lösen Sie die Ausnahme erneut aus.
Behandeln Sie unbekannte Ausnahmen immer so hoch wie möglich - der einzige Code, der eine Ausnahme verbrauchen und nicht erneut auslösen sollte, sollte die Benutzeroberfläche oder die öffentliche API sein.
Angenommen, Sie stellen eine Verbindung zu einer Remote-API her. Hier müssen Sie bestimmte Fehler erwarten (und haben unter diesen Umständen Probleme). Dies ist also Fall 1:
Beachten Sie, dass keine anderen Ausnahmen abgefangen werden, da sie nicht erwartet werden.
Angenommen, Sie versuchen, etwas in der Datenbank zu speichern. Wir müssen es zurücksetzen, wenn es fehlschlägt, also haben wir Fall 2:
Beachten Sie, dass wir die Ausnahme erneut auslösen - der Code weiter oben muss noch wissen, dass etwas fehlgeschlagen ist.
Endlich haben wir die Benutzeroberfläche - hier wollen wir keine völlig unbehandelten Ausnahmen haben, aber wir wollen sie auch nicht verbergen. Hier haben wir ein Beispiel für Fall 3:
Die meisten API- oder UI-Frameworks bieten jedoch generische Methoden für Fall 3. Beispielsweise verfügt ASP.Net über einen gelben Fehlerbildschirm, in dem die Ausnahmedetails ausgegeben werden, der jedoch in der Produktionsumgebung durch eine allgemeinere Meldung ersetzt werden kann. Das Befolgen dieser Anweisungen ist eine bewährte Methode, da Sie viel Code sparen, aber auch, weil die Fehlerprotokollierung und -anzeige eher Konfigurationsentscheidungen als fest codiert sein sollten.
Dies alles bedeutet, dass Fall 1 (bekannte Ausnahmen) und Fall 3 (einmalige Behandlung der Benutzeroberfläche) bessere Muster aufweisen (vermeiden Sie den erwarteten Fehler oder die Handfehlerbehandlung an die Benutzeroberfläche).
Selbst Fall 2 kann durch bessere Muster ersetzt werden. Beispielsweise erschweren Transaktionsbereiche (
using
Blöcke, die Transaktionen zurücksetzen , die während des Blocks nicht festgeschrieben wurden) Entwicklern, das Best-Practice-Muster falsch zu verstehen.Angenommen, Sie haben eine umfangreiche ASP.Net-Anwendung. Die Fehlerprotokollierung kann über ELMAH erfolgen , die Fehleranzeige kann ein informatives YSoD lokal und eine nette lokalisierte Nachricht in der Produktion sein. Datenbankverbindungen können alle über Transaktionsbereiche und
using
-blöcke erfolgen. Sie brauchen keinen einzigentry-catch
Block.TL; DR: Best Practice ist es, überhaupt keine
try-catch
Blöcke zu verwenden.quelle
try-catch
- es kann (sehr gelegentlich) nützlich sein und ich argumentiere nicht, dass Sie sie niemals verwenden sollten, aber in 99% der Fälle gibt es einen besseren Weg.Eine Ausnahme ist ein Blockierungsfehler .
Zunächst sollte die beste Vorgehensweise darin bestehen, keine Ausnahmen für Fehler jeglicher Art auszulösen, es sei denn, es handelt sich um einen Blockierungsfehler .
Wenn der Fehler blockiert , lösen Sie die Ausnahme aus. Sobald die Ausnahme bereits ausgelöst wurde, müssen Sie sie nicht mehr ausblenden, da sie außergewöhnlich ist. Informieren Sie den Benutzer darüber (Sie sollten die gesamte Ausnahme in etwas umformatieren, das für den Benutzer in der Benutzeroberfläche nützlich ist).
Ihre Aufgabe als Softwareentwickler ist es, einen Ausnahmefall zu vermeiden , in dem bestimmte Parameter oder Laufzeitsituationen in einer Ausnahme enden können. Das heißt, Ausnahmen dürfen nicht stummgeschaltet werden, aber diese müssen vermieden werden .
Wenn Sie beispielsweise wissen, dass eine Ganzzahl- Eingabe ein ungültiges Format haben kann, verwenden Sie
int.TryParse
stattdessen anstelle vonint.Parse
. Es gibt viele Fälle, in denen Sie dies tun können, anstatt nur zu sagen: "Wenn dies fehlschlägt, lösen Sie einfach eine Ausnahme aus."Ausnahmen zu werfen ist teuer.
Wenn schließlich eine Ausnahme ausgelöst wird, anstatt die Ausnahme nach dem Auslösen in das Protokoll zu schreiben, besteht eine der besten Methoden darin, sie in einem Ausnahmebehandler der ersten Chance abzufangen . Beispielsweise:
Mein Standpunkt ist, dass lokale Versuche / Fänge besser für die Behandlung von Sonderfällen geeignet sind, in denen Sie eine Ausnahme in eine andere übersetzen können oder wenn Sie sie für einen sehr, sehr, sehr, sehr, sehr speziellen Fall (einen Bibliotheksfehler) "stumm schalten" möchten eine nicht verwandte Ausnahme auslösen, die Sie stummschalten müssen, um den gesamten Fehler zu umgehen).
Für den Rest der Fälle:
Antwort auf @thewhiteambit auf einen Kommentar ...
@thewhiteambit sagte:
Wie kann eine Ausnahme nicht einmal ein Fehler sein?
null
während Objekt erwartet wurde => AusnahmeWir könnten 1k Fälle auflisten, in denen eine Ausnahme ausgelöst wird, und schließlich wird jeder der möglichen Fälle ein Fehler sein .
Eine Ausnahme ist ein Fehler, da es sich letztendlich um ein Objekt handelt, das Diagnoseinformationen sammelt - es hat eine Meldung und es passiert, wenn etwas schief geht.
Niemand würde eine Ausnahme auslösen, wenn es keinen Ausnahmefall gibt. Ausnahmen sollten blockierende Fehler sein, da Ihre Anwendung / Ihr Dienst den Vorgang, der in einen Ausnahmefall eingetreten ist, stoppt , wenn Sie nicht versuchen, in die Verwendung try / catch und Ausnahmen zum Implementieren des Kontrollflusses zu fallen .
Außerdem empfehle ich jedem, das von Martin Fowler veröffentlichte (und von Jim Shore geschriebene) Fail-Fast- Paradigma zu überprüfen . So habe ich immer verstanden, wie man mit Ausnahmen umgeht, noch bevor ich vor einiger Zeit zu diesem Dokument kam.
Normalerweise unterbrechen Ausnahmen den Betriebsablauf und werden so behandelt, dass sie in vom Menschen verständliche Fehler umgewandelt werden. Daher scheint eine Ausnahme tatsächlich ein besseres Paradigma zu sein, um Fehlerfälle zu behandeln und zu bearbeiten, um einen vollständigen Absturz von Anwendung / Dienst zu vermeiden und den Benutzer / Verbraucher darüber zu informieren, dass ein Fehler aufgetreten ist.
Weitere Antworten zu @ thewhiteambit-Bedenken
Wenn Ihre App möglicherweise offline funktioniert, ohne dass Daten in der Datenbank gespeichert werden, sollten Sie keine Ausnahmen verwenden , da die Implementierung des Kontrollflusses mithilfe von
try/catch
als Anti-Pattern betrachtet wird. Offline-Arbeit ist ein möglicher Anwendungsfall. Sie implementieren also den Kontrollfluss, um zu überprüfen, ob auf die Datenbank zugegriffen werden kann oder nicht. Sie warten nicht, bis sie nicht mehr erreichbar ist .Das Parsen ist auch ein erwarteter Fall ( kein AUSSERGEWÖHNLICHER FALL ). Wenn Sie dies erwarten, verwenden Sie keine Ausnahmen, um den Fluss zu steuern! . Sie erhalten vom Benutzer einige Metadaten, um zu wissen, was seine / ihre Kultur ist, und Sie verwenden dafür Formatierer! .NET unterstützt auch diese und andere Umgebungen und eine Ausnahme, da die Formatierung von Zahlen vermieden werden muss, wenn Sie eine kulturspezifische Nutzung Ihrer Anwendung / Ihres Dienstes erwarten .
Dieser Artikel ist nur eine Meinung oder ein Standpunkt des Autors.
Da Wikipedia auch nur die Meinung von Autoren sein kann, würde ich nicht sagen, dass es das Dogma ist , aber überprüfen Sie, was der Artikel Coding by Exception irgendwo in einem Absatz sagt:
Es heißt auch irgendwo:
Falsche Verwendung von Ausnahmen
Ehrlich gesagt glaube ich, dass Software nicht entwickelt werden kann, wenn Anwendungsfälle nicht ernst genommen werden. Wenn Sie das wissen ...
... Sie werden dafür keine Ausnahmen verwenden . Sie würden unterstützen diese Anwendungsfälle mit regelmäßigen Kontrollfluss.
Und wenn ein unerwarteter Anwendungsfall nicht behandelt wird, schlägt Ihr Code schnell fehl, da eine Ausnahme ausgelöst wird . Richtig, denn eine Ausnahme ist ein Ausnahmefall .
Auf der anderen Seite und schließlich decken Sie manchmal Ausnahmefälle ab , die erwartete Ausnahmen auslösen , aber Sie werfen sie nicht aus, um den Kontrollfluss zu implementieren. Sie tun dies, weil Sie den oberen Ebenen mitteilen möchten, dass Sie einen Anwendungsfall nicht unterstützen oder Ihr Code mit bestimmten Argumenten oder Umgebungsdaten / -eigenschaften nicht funktioniert.
quelle
Das einzige Mal, wenn Sie Ihre Benutzer über etwas beunruhigen sollten, das im Code passiert ist, ist, wenn sie etwas tun können oder müssen, um das Problem zu vermeiden. Wenn sie Daten in einem Formular ändern können, drücken Sie eine Taste oder ändern Sie eine Anwendungseinstellung, um das Problem zu vermeiden, und lassen Sie sie dies wissen. Warnungen oder Fehler, die der Benutzer nicht vermeiden kann, führen jedoch dazu, dass er das Vertrauen in Ihr Produkt verliert.
Ausnahmen und Protokolle sind für Sie, den Entwickler, und nicht für Ihren Endbenutzer. Es ist weitaus besser zu verstehen, was zu tun ist, wenn Sie jede Ausnahme abfangen, als nur eine goldene Regel anzuwenden oder sich auf ein anwendungsweites Sicherheitsnetz zu verlassen.
Gedankenlose Codierung ist die EINZIGE Art der falschen Codierung. Die Tatsache, dass Sie der Meinung sind, dass in diesen Situationen etwas Besseres getan werden kann, zeigt, dass Sie in eine gute Codierung investiert sind. Vermeiden Sie es jedoch, in diesen Situationen eine generische Regel zu stempeln, und verstehen Sie den Grund, warum etwas überhaupt geworfen werden muss, und was Sie können tun, um sich davon zu erholen.
quelle
Ich weiß, dass dies eine alte Frage ist, aber hier hat niemand den MSDN-Artikel erwähnt, und es war das Dokument, das ihn tatsächlich für mich geklärt hat. MSDN hat ein sehr gutes Dokument dazu. Sie sollten Ausnahmen abfangen, wenn die folgenden Bedingungen erfüllt sind:
Ich würde empfehlen, den gesamten Abschnitt " Ausnahmen und Ausnahmebehandlung " sowie die Best Practices für Ausnahmen zu lesen .
quelle
Der bessere Ansatz ist der zweite (der, in dem Sie den Ausnahmetyp angeben). Dies hat den Vorteil, dass Sie wissen, dass diese Art von Ausnahme in Ihrem Code auftreten kann. Sie behandeln diese Art von Ausnahme und können fortfahren. Wenn eine andere Ausnahme aufgetreten ist, bedeutet dies, dass etwas nicht stimmt, was Ihnen hilft, Fehler in Ihrem Code zu finden. Die Anwendung wird irgendwann abstürzen, aber Sie werden feststellen, dass Sie etwas verpasst haben (Fehler), das behoben werden muss.
quelle
Mit Ausnahmen versuche ich Folgendes:
Zuerst fange ich spezielle Arten von Ausnahmen wie Division durch Null, E / A-Operationen usw. ab und schreibe entsprechend Code. Zum Beispiel eine Division durch Null, abhängig von der Herkunft der Werte, die ich den Benutzer alarmieren könnte (zum Beispiel ein einfacher Taschenrechner, der in einer mittleren Berechnung (nicht die Argumente) in einer Division durch Null ankommt) oder um diese Ausnahme stillschweigend zu behandeln, Protokollierung es und weiter zu verarbeiten.
Dann versuche ich, die verbleibenden Ausnahmen abzufangen und zu protokollieren. Wenn möglich, erlauben Sie die Ausführung von Code, andernfalls benachrichtigen Sie den Benutzer, dass ein Fehler aufgetreten ist, und bitten Sie ihn, einen Fehlerbericht zu senden.
Im Code so etwas:
quelle
0
vorher nach einem Zähler gesucht wird, anstatt nach atry-catch
. Auch warum das GenerikumException
hier fangen ? Es ist besser, den Fehler in die Luft sprudeln zu lassen, als ihn hier in allen Fällen zu behandeln, in denen Sie ihn nicht erwarten.Der zweite Ansatz ist gut.
Wenn Sie den Fehler nicht anzeigen und den Benutzer der Anwendung verwirren möchten, indem Sie eine Laufzeitausnahme (dh einen Fehler) anzeigen, die nicht mit ihnen zusammenhängt, protokollieren Sie einfach den Fehler, und das technische Team kann nach dem Problem suchen und es beheben.
Ich empfehle Ihnen, den zweiten Ansatz für Ihre gesamte Anwendung zu wählen.
quelle
catch
Blöcke sollten immer entweder aufrufen,throw
um die Ausnahme zu aktivieren oder etwas zurückzugeben / etwas anzuzeigen, das dem Benutzer mitteilt, dass die Aktion fehlgeschlagen ist. Sie möchten den Support-Anruf erhalten, wenn sie nicht speichern, was auch immer es ist, und nicht 6 Monate später, wenn sie versuchen, es abzurufen und es nicht finden können.Leeren Fangblock lassen ist das Schlimmste. Wenn ein Fehler auftritt, können Sie ihn am besten beheben:
quelle
Die Behandlung von Ausnahmen kann für mich als Geschäftsregel angesehen werden. Offensichtlich ist der erste Ansatz nicht akzeptabel. Der zweite ist besser und könnte zu 100% korrekt sein, wenn der Kontext dies sagt. Jetzt entwickeln Sie beispielsweise ein Outlook-Add-In. Wenn Sie beim Add-In eine nicht behandelte Ausnahme auslösen, weiß dies möglicherweise der Outlook-Benutzer, da sich der Outlook aufgrund eines fehlgeschlagenen Plugins nicht selbst zerstört. Und es fällt Ihnen schwer herauszufinden, was schief gelaufen ist. Daher ist der zweite Ansatz in diesem Fall für mich der richtige. Neben der Protokollierung der Ausnahme können Sie sich auch dafür entscheiden, dem Benutzer eine Fehlermeldung anzuzeigen - ich betrachte dies als Geschäftsregel.
quelle
Es wird empfohlen, eine Ausnahme auszulösen, wenn der Fehler auftritt. Weil ein Fehler aufgetreten ist und dieser nicht ausgeblendet werden sollte.
Aber im wirklichen Leben kann es mehrere Situationen geben, in denen Sie dies verbergen möchten
quelle
Exception
. Je. Werfen Sie eine geeignete Unterklasse vonException
allem, was Sie wollen, aber niemals,Exception
weil dies absolut keine semantischen Informationen liefert. Ich kann kein Szenario sehen, in dem es sinnvoll ist, zu werfen,Exception
aber keine Unterklasse davon.Sie sollten diese Gestaltungsrichtlinien für Ausnahmen berücksichtigen
https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/exceptions
quelle
Das
catch
ohne Argumente frisst einfach die Ausnahme und nützt nichts. Was ist, wenn ein schwerwiegender Fehler auftritt? Es gibt keine Möglichkeit zu wissen, was passiert ist, wenn Sie catch ohne Argument verwenden.Eine catch-Anweisung sollte spezifischere Ausnahmen wie abfangen,
FileNotFoundException
und ganz am Ende sollten Sie abfangen,Exception
welche andere Ausnahmen abfangen und protokollieren würden.quelle
catch(Exception)
am Ende einen General ? Wenn Sie es nicht erwarten, ist es immer empfehlenswert, es an die nächste Ebene weiterzugeben.Manchmal müssen Sie Ausnahmen behandeln, die den Benutzern nichts sagen.
Mein Weg ist:
Es muss definitiv keine Best Practice sein. ;-);
quelle
Ich kann dir etwas sagen:
Snippet Nr. 1 ist nicht akzeptabel, da Ausnahmen ignoriert werden. (Es schluckt es, als wäre nichts passiert).
Fügen Sie also keinen Fangblock hinzu, der nichts tut oder nur neu wirft.
Der Catch-Block sollte einen Mehrwert bieten. Zum Beispiel Nachricht an Endbenutzer ausgeben oder Fehler protokollieren.
Verwenden Sie keine Ausnahme für die normale Ablaufprogrammlogik. Beispielsweise:
zB Eingabevalidierung. <- Dies ist keine gültige Ausnahmesituation. Sie sollten vielmehr eine Methode schreiben, um
IsValid(myInput);
zu überprüfen, ob das Eingabeelement gültig ist oder nicht.Designcode zur Vermeidung von Ausnahmen. Beispielsweise:
Wenn wir einen Wert übergeben, der nicht an int analysiert werden kann, würde diese Methode eine Ausnahme auslösen, stattdessen könnten wir Folgendes schreiben:
bool TryParse(string input,out int result);
<- Diese Methode würde einen Booleschen Wert zurückgeben, der angibt, ob die Analyse erfolgreich war.Vielleicht liegt dies etwas außerhalb des Rahmens dieser Frage, aber ich hoffe, dies wird Ihnen helfen, die richtigen Entscheidungen zu treffen, wenn es um
try {} catch(){}
Ausnahmen geht.quelle