Ich habe in einem unserer Projekte einen Code wie diesen gefunden:
SomeClass QueryServer(string args)
{
try
{
return SomeClass.Parse(_server.Query(args));
}
catch (Exception)
{
return null;
}
}
Soweit ich weiß, ist das Unterdrücken derartiger Fehler eine schlechte Praxis, da hierdurch nützliche Informationen aus der Ausnahme des ursprünglichen Servers gelöscht werden und der Code fortgesetzt wird, wenn er tatsächlich beendet werden sollte.
Wann ist es angebracht, alle derartigen Fehler vollständig zu unterdrücken?
Antworten:
Stellen Sie sich Code mit Tausenden von Dateien mit einer Reihe von Bibliotheken vor. Stellen Sie sich vor, alle sind so codiert.
Stellen Sie sich beispielsweise vor, ein Update Ihres Servers führt dazu, dass eine Konfigurationsdatei verschwindet. Wenn Sie versuchen, diese Klasse zu verwenden, ist ein Stack-Trace eine Nullzeiger-Ausnahme. Wie würden Sie das beheben? Es kann Stunden dauern, bis Sie möglicherweise nur den unformatierten Stack-Trace der nicht gefundenen Datei [Dateipfad] protokollieren und diese vorübergehend beheben können.
Oder noch schlimmer: ein Fehler in einer der Bibliotheken, die Sie nach einem Update verwenden, das Ihren Code später zum Absturz bringt. Wie können Sie dies zurück in die Bibliothek verfolgen?
Auch ohne robuste Fehlerbehandlung einfach machen
oder
kann Ihnen Stunden Zeit sparen.
Es gibt jedoch einige Fälle, in denen Sie die Ausnahme wirklich ignorieren und null wie folgt zurückgeben möchten (oder nichts tun). Vor allem, wenn Sie schlecht gestalteten Legacy-Code integrieren und diese Ausnahme als normaler Fall erwartet wird.
Wenn Sie dies tun, sollten Sie sich nur fragen, ob Sie die Ausnahmebedingung oder die "ordnungsgemäße Behandlung" für Ihre Anforderungen wirklich ignorieren. Wenn die Rückgabe von null in diesem Fall Ihre Ausnahme "richtig behandelt", dann tun Sie es. Und fügen Sie einen Kommentar hinzu, warum dies das Richtige ist.
Best Practices sind in den meisten Fällen zu befolgen, vielleicht 80%, vielleicht 99%, aber Sie werden immer einen Randfall finden, in dem sie nicht zutreffen. In diesem Fall hinterlassen Sie einen Kommentar, warum Sie die Praxis nicht für die anderen (oder sogar für sich selbst) befolgen, die Ihren Code Monate später lesen.
quelle
Es gibt Fälle, in denen dieses Muster nützlich ist - es wird jedoch normalerweise verwendet, wenn die generierte Ausnahme niemals hätte auftreten dürfen (dh wenn Ausnahmen für normales Verhalten verwendet werden).
Angenommen, Sie haben eine Klasse, die eine Datei öffnet und in dem zurückgegebenen Objekt speichert. Wenn die Datei nicht vorhanden ist, können Sie davon ausgehen, dass dies kein Fehlerfall ist. Geben Sie null zurück und lassen Sie den Benutzer stattdessen eine neue Datei erstellen. Die Methode zum Öffnen von Dateien kann hier eine Ausnahme auslösen, um darauf hinzuweisen, dass keine Datei vorhanden ist. Daher kann ein unbemerktes Abfangen eine gültige Situation sein.
Es ist jedoch selten, dass Sie dies tun möchten, und wenn der Code mit einem solchen Muster übersät ist, möchten Sie sich jetzt damit befassen. Zumindest würde ich erwarten, dass solch ein stiller Fang eine Protokollzeile schreibt, die besagt, dass dies geschehen ist (Sie haben eine Ablaufverfolgung, richtig) und einen Kommentar, um dieses Verhalten zu erklären.
quelle
null
.Dies ist zu 100% kontextabhängig. Wenn der Aufrufer einer solchen Funktion die Anforderung hat, Fehler irgendwo anzuzeigen oder zu protokollieren, ist dies offensichtlich Unsinn. Wenn der Aufrufer auch alle Fehler- oder Ausnahmemeldungen ignoriert, ist es wenig sinnvoll, die Ausnahme oder ihre Meldung zurückzugeben. Wenn der Code nur beendet werden soll, ohne dass ein Grund angezeigt wird, dann ein Anruf
würde wohl ausreichen. Sie müssen sich überlegen, ob es dadurch für den Benutzer schwierig wird, die Fehlerursache zu finden. Ist dies der Fall, ist dies die falsche Form der Fehlerbehandlung. Wenn der aufrufende Code jedoch so aussieht
Dann sollten Sie während der Codeüberprüfung einen Streit mit dem Entwickler haben. Wenn jemand eine solche Form der fehlerfreien Behandlung implementiert, nur weil er zu faul ist, um die richtigen Anforderungen herauszufinden, sollte dieser Code nicht in Produktion gehen, und der Autor des Codes sollte über die möglichen Folgen einer solchen Faulheit unterrichtet werden .
quelle
In den Jahren, in denen ich Systeme programmiert und entwickelt habe, gab es nur zwei Situationen, in denen ich das fragliche Muster als nützlich empfand (in beiden Fällen betrachte ich die Unterdrückung, die auch die Protokollierung der ausgelösten Ausnahme enthielt, nicht
null
als eine gute Praxis ).Die zwei Situationen sind die folgenden:
1. Wenn die Ausnahme nicht als Ausnahmezustand angesehen wurde
In diesem Fall führen Sie eine Operation für einige Daten aus, die möglicherweise ausgelöst werden, von denen Sie wissen, dass sie ausgelöst werden. Sie möchten jedoch weiterhin, dass Ihre Anwendung ausgeführt wird, da Sie die verarbeiteten Daten nicht benötigen. Wenn Sie sie erhalten, ist es gut, wenn Sie es nicht tun, ist es auch gut.
Einige optionale Attribute einer Klasse können in den Sinn kommen.
2. Wenn Sie eine neue (bessere, schnellere?) Implementierung einer Bibliothek über eine Schnittstelle bereitstellen, die bereits in einer Anwendung verwendet wird
Stellen Sie sich vor, Sie haben eine Anwendung, die eine Art alte Bibliothek verwendet, die keine Ausnahmen ausgelöst hat, sondern
null
bei einem Fehler zurückgegeben wurde. Sie haben also einen Adapter für diese Bibliothek erstellt, indem Sie die ursprüngliche API der Bibliothek kopiert haben, und verwenden diese neue (immer noch nicht auslösende) Schnittstelle in Ihrer Anwendung, um dienull
Prüfungen selbst durchzuführen.Es kommt eine neue Version der Bibliothek oder eine völlig andere Bibliothek mit derselben Funktionalität, die anstelle von
null
s Ausnahmen auslöst und die Sie verwenden möchten.Sie möchten die Ausnahmen nicht an Ihre Hauptanwendung weitergeben, daher unterdrücken und protokollieren Sie sie in dem Adapter, den Sie erstellen, um diese neue Abhängigkeit zu verpacken.
Der erste Fall ist kein Problem, sondern das gewünschte Verhalten des Codes. Wenn jedoch in der zweiten Situation der
null
Rückgabewert des Bibliotheksadapters überall wirklich einen Fehler bedeutet, ist esnull
möglicherweise eine gute Idee , die API so umzugestalten, dass eine Ausnahme ausgelöst und abgefangen wird, anstatt zu prüfen (und dies ist in der Regel im Code der Fall).Ich persönlich verwende Ausnahmesuppression nur für den ersten Fall. Ich habe es nur für den zweiten Fall verwendet, als wir nicht das Budget hatten, um den Rest der Anwendung mit den Ausnahmen anstelle von
null
s zum Laufen zu bringen .quelle
Während es logisch erscheint zu sagen, dass Programme nur Ausnahmen abfangen sollten, mit denen sie umgehen können, und möglicherweise nicht wissen können, wie mit Ausnahmen umzugehen ist, die vom Programmierer nicht erwartet wurden, ignoriert eine solche Behauptung die Tatsache, dass viele Vorgänge in a fehlschlagen können eine nahezu unbegrenzte Anzahl von Möglichkeiten, die keine Nebenwirkungen haben, und dass in vielen Fällen die ordnungsgemäße Behandlung für die überwiegende Mehrheit solcher Fehler identisch sein wird; Die genauen Details des Fehlers sind irrelevant, und folglich sollte es egal sein, ob der Programmierer sie vorweggenommen hat.
Wenn der Zweck einer Funktion beispielsweise darin besteht, eine Dokumentdatei in ein geeignetes Objekt einzulesen und entweder ein neues Dokumentfenster zu erstellen, um dieses Objekt anzuzeigen, oder dem Benutzer zu melden, dass die Datei nicht gelesen werden konnte, versuchen Sie, eine zu laden Eine ungültige Dokumentdatei sollte die Anwendung nicht zum Absturz bringen. Stattdessen sollte eine Meldung angezeigt werden, die auf das Problem hinweist. Der Rest der Anwendung sollte jedoch normal weiterlaufen, es sei denn, der Versuch, das Dokument zu laden, hat aus irgendeinem Grund den Status eines anderen Elements im System beschädigt .
Grundsätzlich hängt die ordnungsgemäße Behandlung einer Ausnahme häufig weniger vom Ausnahmetyp ab als vom Ort, an dem sie ausgelöst wurde. Wenn eine Ressource durch eine Lese- / Schreibsperre geschützt ist und eine Ausnahme innerhalb einer Methode ausgelöst wird, die die Lesesperre erhalten hat, sollte das ordnungsgemäße Verhalten im Allgemeinen darin bestehen, die Sperre aufzuheben, da die Methode der Ressource nichts anhaben kann . Wenn eine Ausnahme ausgelöst wird, während die Sperre zum Schreiben angefordert wird, sollte die Sperre häufig ungültig gemacht werden, da sich die geschützte Ressource möglicherweise in einem ungültigen Zustand befindet. Wenn das Sperrprimitiv keinen "ungültigen" Zustand aufweist, sollte ein Flag hinzugefügt werden, um eine solche Ungültigmachung zu verfolgen. Das Aufheben der Sperre, ohne sie zu ungültig zu machen, ist fehlerhaft, da andere Codes das geschützte Objekt möglicherweise in einem ungültigen Zustand sehen. Das Schloss baumeln zu lassen ist jedoch nicht Auch eine richtige Lösung. Die richtige Lösung besteht darin, die Sperre aufzuheben, damit anstehende oder zukünftige Erfassungsversuche sofort fehlschlagen.
Wenn sich herausstellt, dass eine ungültige Ressource vor dem Versuch, sie zu verwenden, verworfen wird, besteht kein Grund, die Anwendung herunterzufahren. Wenn eine ungültig gemachte Ressource für den weiteren Betrieb einer Anwendung von entscheidender Bedeutung ist, muss die Anwendung heruntergefahren werden. Wenn die Ressource jedoch ungültig gemacht wird, ist dies wahrscheinlich. Der Code, der die ursprüngliche Ausnahme erhalten hat, kann häufig nicht wissen, welche Situation zutrifft. Wenn er jedoch die Ressource ungültig macht, kann er sicherstellen, dass in beiden Fällen die richtige Aktion ausgeführt wird.
quelle
Das Verschlucken eines solchen Fehlers ist für niemanden besonders nützlich. Ja, der ursprüngliche Anrufer kann über die Ausnahme , aber jemand anderes nicht kümmern könnte .
Was machen sie dann? Sie fügen Code zur Behandlung der Ausnahme hinzu, um festzustellen, welche Art von Ausnahme sie zurückerhalten. Groß. Wenn die Ausnahmebehandlung jedoch aktiviert bleibt, erhält der ursprüngliche Aufrufer keine Null mehr und an anderer Stelle bricht etwas zusammen.
Selbst wenn Sie wissen, dass ein Upstream-Code einen Fehler auslösen und somit null zurückgeben kann, wäre es für Sie äußerst träge, zumindest nicht zu versuchen, die Ausnahme im aufrufenden Code IMHO auszulösen.
quelle
Ich habe Beispiele gesehen, in denen Bibliotheken von Drittanbietern möglicherweise nützliche Methoden hatten, mit der Ausnahme, dass sie in einigen Fällen Ausnahmen auslösen, die für mich funktionieren sollten. Was kann ich tun?
Zum Beispiel die Bibliotheksmethode
Gibt das erste foo zurück, aber wenn es keins gibt, wird eine Ausnahme ausgelöst. Aber was ich brauche, ist eine Methode, um das erste foo oder eine Null zurückzugeben. Also schreibe ich diesen:
Nicht ordentlich. Aber manchmal die pragmatische Lösung.
quelle