Ich habe Leute sagen sehen, dass es eine schlechte Form ist, catch ohne Argumente zu verwenden, besonders wenn dieser catch nichts bewirkt:
StreamReader reader=new StreamReader("myfile.txt");
try
{
int i = 5 / 0;
}
catch // No args, so it will catch any exception
{}
reader.Close();
Dies wird jedoch als gute Form angesehen:
StreamReader reader=new StreamReader("myfile.txt");
try
{
int i = 5 / 0;
}
finally // Will execute despite any exception
{
reader.Close();
}
Soweit ich das beurteilen kann, besteht der einzige Unterschied zwischen dem Einfügen von Bereinigungscode in einen finally-Block und dem Einfügen von Bereinigungscode nach den try..catch-Blöcken darin, dass Sie return-Anweisungen in Ihrem try-Block haben (in diesem Fall wird der Bereinigungscode in finally-Blöcken verwendet ausführen, aber Code nach dem try..catch wird nicht).
Ansonsten, was ist das Besondere an Endlich?
c#
.net
exception-handling
try-catch
try-catch-finally
mbeckisch
quelle
quelle
Antworten:
Der große Unterschied besteht darin, dass
try...catch
die Ausnahme verschluckt wird und die Tatsache verborgen bleibt, dass ein Fehler aufgetreten ist.try..finally
führt Ihren Bereinigungscode aus und dann wird die Ausnahme fortgesetzt, um von etwas behandelt zu werden, das weiß, was damit zu tun ist.quelle
"Schließlich" ist eine Aussage von "Etwas, das Sie immer tun müssen, um sicherzustellen, dass der Programmstatus gesund ist". Daher ist es immer eine gute Form, eine zu haben, wenn die Möglichkeit besteht, dass Ausnahmen den Programmstatus beeinträchtigen. Der Compiler unternimmt auch große Anstrengungen, um sicherzustellen, dass Ihr Endlich-Code ausgeführt wird.
"Catch" ist eine Aussage von "Ich kann mich von dieser Ausnahme erholen". Sie sollten sich nur von Ausnahmen erholen, die Sie wirklich korrigieren können - catch ohne Argumente sagt "Hey, ich kann mich von allem erholen!", Was fast immer falsch ist.
Wenn es möglich wäre, sich von jeder Ausnahme zu erholen, wäre es wirklich ein semantischer Streit darüber, was Sie als Ihre Absicht deklarieren. Dies ist jedoch nicht der Fall, und mit ziemlicher Sicherheit sind Frames über Ihren für bestimmte Ausnahmen besser gerüstet. Verwenden Sie daher endlich, lassen Sie Ihren Bereinigungscode kostenlos ausführen, und lassen Sie dennoch sachkundigere Handler das Problem lösen.
quelle
Denn wenn diese eine einzelne Zeile eine Ausnahme auslöst, würden Sie es nicht wissen.
Mit dem ersten Codeblock wird die Ausnahme einfach absorbiert und das Programm wird auch dann weiter ausgeführt, wenn der Status des Programms möglicherweise falsch ist.
Mit dem zweiten Block wird die Ausnahme ausgelöst und sprudelt, aber die
reader.Close()
Ausführung wird garantiert.Wenn eine Ausnahme nicht erwartet wird, setzen Sie keinen try..catch-Block, es ist später schwierig zu debuggen, wenn das Programm in einen schlechten Zustand versetzt wurde und Sie keine Ahnung haben, warum.
quelle
Schließlich wird egal was ausgeführt. Wenn Ihr try-Block erfolgreich war, wird er ausgeführt. Wenn Ihr try-Block fehlschlägt, wird der catch-Block und dann der finally-Block ausgeführt.
Versuchen Sie auch, das folgende Konstrukt zu verwenden:
Da die using-Anweisung automatisch in einen try / finally-Code eingeschlossen wird, wird der Stream automatisch geschlossen. (Sie müssen die using-Anweisung mit try / catch versehen, wenn Sie die Ausnahme tatsächlich abfangen möchten.)
quelle
Die folgenden 2 Codeblöcke sind zwar äquivalent, aber nicht gleich.
Schließlich sind Blöcke etwas Besonderes. Die CLR erkennt und behandelt Code mit einem finally-Block getrennt von catch-Blöcken, und die CLR unternimmt große Anstrengungen, um sicherzustellen, dass ein finally-Block immer ausgeführt wird. Es ist nicht nur syntaktischer Zucker vom Compiler.
quelle
Ich stimme dem zu, was hier der Konsens zu sein scheint - ein leerer "Fang" ist schlecht, weil er jede Ausnahme maskiert, die im try-Block aufgetreten sein könnte.
Unter dem Gesichtspunkt der Lesbarkeit gehe ich auch davon aus, dass es eine entsprechende 'catch'-Anweisung gibt, wenn ich einen' try'-Block sehe. Wenn Sie nur einen 'try' verwenden, um sicherzustellen, dass die Ressourcen im 'finally'-Block freigegeben werden, können Sie stattdessen die ' using'-Anweisung in Betracht ziehen :
Sie können die Anweisung 'using' für jedes Objekt verwenden, das IDisposable implementiert. Die dispose () -Methode des Objekts wird am Ende des Blocks automatisch aufgerufen.
quelle
Verwenden
Try..Catch..Finally
Sie diese Option , wenn Ihre Methode weiß, wie die Ausnahme lokal behandelt wird. Die Ausnahme tritt in Try, Handled in Catch und danach in Endlich auf.Falls Ihre Methode nicht weiß, wie die Ausnahme zu behandeln ist, aber eine Bereinigung benötigt, sobald sie aufgetreten ist, verwenden Sie sie
Try..Finally
Auf diese Weise wird die Ausnahme an die aufrufenden Methoden weitergegeben und behandelt, wenn die aufrufenden Methoden geeignete Catch-Anweisungen enthalten. Wenn die aktuelle Methode oder eine der aufrufenden Methoden keine Ausnahmebehandlungsroutinen enthält, stürzt die Anwendung ab.
Dadurch
Try..Finally
wird sichergestellt, dass die lokale Bereinigung durchgeführt wird, bevor die Ausnahme an die aufrufenden Methoden weitergegeben wird.quelle
Der try..finally-Block löst weiterhin alle Ausnahmen aus, die ausgelöst werden. Sie
finally
müssen lediglich sicherstellen, dass der Bereinigungscode ausgeführt wird, bevor die Ausnahme ausgelöst wird.Der try..catch mit einem leeren catch verbraucht jede Ausnahme vollständig und verbirgt die Tatsache, dass es passiert ist. Der Leser wird geschlossen, aber es ist nicht abzusehen, ob das Richtige passiert ist. Was wäre, wenn Sie beabsichtigen würden, i in die Datei zu schreiben ? In diesem Fall schaffen Sie es nicht zu diesem Teil des Codes und myfile.txt ist leer. Behandeln alle nachgeschalteten Methoden dies ordnungsgemäß? Wenn Sie die leere Datei sehen, können Sie dann richtig erraten, dass sie leer ist, weil eine Ausnahme ausgelöst wurde? Es ist besser, die Ausnahme auszulösen und bekannt zu geben, dass Sie etwas falsch machen.
Ein weiterer Grund ist der Versuch ... ein solcher Fang ist völlig falsch. Was Sie damit sagen, ist: "Egal was passiert, ich kann damit umgehen." Was ist mit
StackOverflowException
, kannst du danach aufräumen? Was ist mitOutOfMemoryException
? Im Allgemeinen sollten Sie nur Ausnahmen behandeln, die Sie erwarten und die Sie behandeln können.quelle
Wenn Sie nicht wissen, welchen Ausnahmetyp Sie abfangen sollen oder was Sie damit tun sollen, macht es keinen Sinn, eine catch-Anweisung zu haben. Sie sollten es nur einem höheren Anrufer überlassen, der möglicherweise mehr Informationen über die Situation hat, um zu wissen, was zu tun ist.
Sie sollten dort immer noch eine finally-Anweisung haben, falls es eine Ausnahme gibt, damit Sie Ressourcen bereinigen können, bevor diese Ausnahme an den Aufrufer gesendet wird.
quelle
Aus Sicht der Lesbarkeit wird zukünftigen Code-Lesern expliziter gesagt: "Dieses Zeug hier ist wichtig, es muss getan werden, egal was passiert." Das ist gut.
Außerdem neigen leere Fanganweisungen dazu, einen bestimmten "Geruch" zu haben. Sie könnten ein Zeichen dafür sein, dass Entwickler nicht über die verschiedenen Ausnahmen nachdenken, die auftreten können, und wie sie damit umgehen sollen.
quelle
Schließlich ist optional - es gibt keinen Grund, einen "Endlich" -Block zu haben, wenn keine Ressourcen zum Bereinigen vorhanden sind.
quelle
Entnommen aus: hier
Das Auslösen und Abfangen von Ausnahmen sollte im Rahmen der erfolgreichen Ausführung einer Methode nicht routinemäßig erfolgen. Bei der Entwicklung von Klassenbibliotheken muss dem Clientcode die Möglichkeit gegeben werden, auf eine Fehlerbedingung zu testen, bevor eine Operation ausgeführt wird, die dazu führen kann, dass eine Ausnahme ausgelöst wird. Beispielsweise bietet System.IO.FileStream eine CanRead-Eigenschaft, die vor dem Aufrufen der Read-Methode überprüft werden kann, um zu verhindern, dass eine potenzielle Ausnahme ausgelöst wird, wie im folgenden Codeausschnitt dargestellt:
Dim str As Stream = GetStream () If (str.CanRead) Dann 'Code zum Lesen des Streams End If
Die Entscheidung, ob der Status eines Objekts vor dem Aufrufen einer bestimmten Methode überprüft werden soll, die eine Ausnahme auslösen kann, hängt vom erwarteten Status des Objekts ab. Wenn ein FileStream-Objekt mit einem Dateipfad erstellt wird, der vorhanden sein sollte, und einem Konstruktor, der eine Datei im Lesemodus zurückgeben soll, ist das Überprüfen der CanRead-Eigenschaft nicht erforderlich. Die Unfähigkeit, den FileStream zu lesen, würde das erwartete Verhalten der durchgeführten Methodenaufrufe verletzen, und es sollte eine Ausnahme ausgelöst werden. Wenn im Gegensatz dazu dokumentiert ist, dass eine Methode eine FileStream-Referenz zurückgibt, die möglicherweise lesbar ist oder nicht, empfiehlt es sich, die CanRead-Eigenschaft zu überprüfen, bevor Sie versuchen, Daten zu lesen.
Um die Auswirkungen auf die Leistung zu veranschaulichen, die die Verwendung einer Codierungstechnik "Bis Ausnahme ausführen" verursachen kann, wird die Leistung einer Umwandlung, die eine InvalidCastException auslöst, wenn die Umwandlung fehlschlägt, mit dem Operator C # as verglichen, der Nullen zurückgibt, wenn eine Umwandlung fehlschlägt. Die Leistung der beiden Techniken ist für den Fall identisch, in dem die Besetzung gültig ist (siehe Test 8.05), aber für den Fall, dass die Besetzung ungültig ist und die Verwendung einer Besetzung eine Ausnahme verursacht, ist die Verwendung einer Besetzung 600-mal langsamer als die Verwendung von als Bediener (siehe Test 8.06). Die Hochleistungseffekte der Ausnahmeauslösungstechnik umfassen die Kosten für das Zuweisen, Auslösen und Abfangen der Ausnahme sowie die Kosten für die nachfolgende Speicherbereinigung des Ausnahmeobjekts, was bedeutet, dass die unmittelbare Auswirkung des Auslösens einer Ausnahme nicht so hoch ist. Wenn mehr Ausnahmen geworfen werden,
quelle
Es ist eine schlechte Praxis, eine catch-Klausel hinzuzufügen, um die Ausnahme erneut auszulösen.
quelle
Wenn Sie C # für Programmierer lesen, werden Sie verstehen, dass der finally-Block dazu gedacht war, eine Anwendung zu optimieren und Speicherverluste zu verhindern.
Wenn Sie beispielsweise eine Datei- oder Datenbankverbindung öffnen, weist Ihr Computer Speicher für diese Transaktion zu, und dieser Speicher wird nur beibehalten, wenn der Befehl disposed oder close ausgeführt wurde. Wenn jedoch während der Transaktion ein Fehler aufgetreten ist, wird der fortlaufende Befehl nur beendet, wenn er sich innerhalb des
try.. finally..
Blocks befindet.catch
war anders alsfinally
in dem Sinne, dass catch so konzipiert war, dass Sie den Fehler selbst handhaben / verwalten oder interpretieren können. Stellen Sie sich das als eine Person vor, die Ihnen sagt: "Hey, ich habe ein paar Bösewichte erwischt. Was soll ich ihnen antun?" whilefinally
wurde entwickelt, um sicherzustellen, dass Ihre Ressourcen ordnungsgemäß platziert wurden. Denken Sie an jemanden, der dafür sorgt, dass Ihr Eigentum noch sicher ist, unabhängig davon, ob es Bösewichte gibt oder nicht.Und Sie sollten diesen beiden erlauben, für immer zusammenzuarbeiten.
beispielsweise:
quelle
Mit finally können Sie Ressourcen bereinigen, auch wenn Ihre catch-Anweisung die Ausnahme bis zum aufrufenden Programm auslöst. Bei Ihrem Beispiel mit der leeren catch-Anweisung gibt es kaum einen Unterschied. Wenn Sie jedoch in Ihrem Fang etwas verarbeiten und den Fehler auslösen oder gar keinen Fang haben, wird der Fehler immer noch ausgeführt.
quelle
Zum einen ist es eine schlechte Praxis, Ausnahmen zu fangen, mit denen Sie sich nicht befassen müssen. Lesen Sie Kapitel 5 über die .NET-Leistung, indem Sie die Leistung und Skalierbarkeit von .NET-Anwendungen verbessern . Nebenbei bemerkt, Sie sollten den Stream wahrscheinlich in den try-Block laden. Auf diese Weise können Sie die entsprechende Ausnahme abfangen, wenn sie fehlschlägt. Das Erstellen des Streams außerhalb des try-Blocks macht seinen Zweck zunichte.
quelle
Unter wahrscheinlich vielen Gründen sind Ausnahmen sehr langsam auszuführen. Sie können Ihre Ausführungszeiten leicht verkürzen, wenn dies häufig vorkommt.
quelle
Das Problem mit Try / Catch-Blöcken, die alle Ausnahmen abfangen, besteht darin, dass sich Ihr Programm jetzt in einem unbestimmten Zustand befindet, wenn eine unbekannte Ausnahme auftritt. Dies verstößt vollständig gegen die Fail-Fast-Regel. Sie möchten nicht, dass Ihr Programm fortgesetzt wird, wenn eine Ausnahme auftritt. Der obige Versuch / Fang würde sogar OutOfMemoryExceptions abfangen, aber das ist definitiv ein Zustand, in dem Ihr Programm nicht ausgeführt wird.
Mit Try / finally-Blöcken können Sie Bereinigungscode ausführen, ohne dass dies schnell fehlschlägt. In den meisten Fällen möchten Sie nur alle Ausnahmen auf globaler Ebene abfangen, damit Sie sie protokollieren und dann beenden können.
quelle
Der effektive Unterschied zwischen Ihren Beispielen ist vernachlässigbar, solange keine Ausnahmen ausgelöst werden.
Wenn jedoch in der 'try'-Klausel eine Ausnahme ausgelöst wird, wird sie im ersten Beispiel vollständig verschluckt. Das zweite Beispiel löst die Ausnahme für den nächsten Schritt im Aufrufstapel aus. Der Unterschied in den angegebenen Beispielen besteht darin, dass eine alle Ausnahmen vollständig verdeckt (erstes Beispiel) und die andere (zweites Beispiel) Ausnahmeinformationen für eine mögliche spätere Behandlung beibehält Der Inhalt in der Klausel 'finally' wird weiterhin ausgeführt.
Wenn Sie beispielsweise Code in die 'catch'-Klausel des ersten Beispiels einfügen, das eine Ausnahme auslöst (entweder die ursprünglich ausgelöste oder eine neue), wird der Reader-Bereinigungscode niemals ausgeführt. Wird schließlich ausgeführt, unabhängig davon, was in der 'catch'-Klausel passiert.
Der Hauptunterschied zwischen 'catch' und 'finally' besteht also darin, dass der Inhalt des Blocks 'finally' (mit wenigen seltenen Ausnahmen) auch bei unerwarteten Ausnahmen als garantiert ausgeführt werden kann, während Code folgt Eine 'catch'-Klausel (aber außerhalb einer' finally'-Klausel) würde eine solche Garantie nicht beinhalten.
Im Übrigen implementieren Stream und StreamReader beide IDisposable und können in einen 'using'-Block eingeschlossen werden. 'Using'-Blöcke sind das semantische Äquivalent von try / finally (kein' catch '), sodass Ihr Beispiel enger ausgedrückt werden könnte als:
... die die StreamReader-Instanz schließen und entsorgen, wenn sie den Gültigkeitsbereich verlässt. Hoffe das hilft.
quelle
try {…} catch {} ist nicht immer schlecht. Es ist kein allgemeines Muster, aber ich neige dazu, es zu verwenden, wenn ich Ressourcen herunterfahren muss, egal was passiert, wie das Schließen eines (möglicherweise) offenen Sockets am Ende eines Threads.
quelle