Ich überprüfe einen Code für einen Freund und sage, dass er eine return-Anweisung in einem Try-finally-Block verwendet hat. Wird der Code im Abschnitt "Endlich" immer noch ausgelöst, obwohl der Rest des try-Blocks dies nicht tut?
Beispiel:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
c#
.net
exception-handling
try-catch
JamesEggers
quelle
quelle
StackOverflowException
,ExecutionEngineException
sind einige davon. Und da sie nicht gehandhabt werden können,finally
laufen sie nicht.try
Block zurückzukehren. Nichts über abrupte Programmabbrüche.try
Blocks ist einereturn
Anweisung. (Die zweite Anweisung dieses Blocks ist nicht erreichbar und generiert eine Warnung.)Antworten:
Einfache Antwort: Ja.
quelle
finally
Block ausgeführt , es sei denn, der gesamte Prozess wird abgebrochen .Normalerweise ja. Es wird garantiert, dass der Abschnitt finally ausgeführt wird, was auch immer passiert, einschließlich Ausnahmen oder return-Anweisungen. Eine Ausnahme von dieser Regel ist eine asynchrone Ausnahme, die im Thread (
OutOfMemoryException
,StackOverflowException
) auftritt .Weitere Informationen zu asynchronen Ausnahmen und zuverlässigem Code in diesen Situationen finden Sie in den eingeschränkten Ausführungsbereichen .
quelle
Hier ist ein kleiner Test:
Das Ergebnis ist:
quelle
WriteLine
Ergebnis des Methodenaufrufs tatsächlich ausgeführt wird. In diesem Fallreturn
legt der Aufruf das Methodenergebnis fest und schreibt schließlich in die Konsole - bevor die Methode beendet wird. DannWriteLine
spuckt die in der Main-Methode den Text aus dem Rückruf aus.Zitieren aus MSDN
quelle
finally
in der jetzigen Form einfach falsch: Sie garantiert sogar nichts für ganz normale Programme (die diese Ausnahme ausgelöst haben).Generell ja, das läuft endlich.
Für die folgenden drei Szenarien wird das endlich IMMER ausgeführt:
Dies umfasst CLS-kompatible Ausnahmen, die von System.Exception abgeleitet sind, und nicht CLS-kompatible Ausnahmen, die nicht von System.Exception abgeleitet sind. Nicht CLS-kompatible Ausnahmen werden automatisch von der RuntimeWrappedException umbrochen. C # kann keine Nicht-CLS-Beschwerdeausnahmen auslösen, Sprachen wie C ++ jedoch. C # ruft möglicherweise Code auf, der in einer Sprache geschrieben ist, die nicht CLS-kompatible Ausnahmen auslösen kann.
Ab .NET 2.0 verhindert eine ThreadAbortException nicht mehr, dass eine endgültige Ausführung ausgeführt wird. ThreadAbortException wird jetzt vor oder nach dem endgültigen angehoben. Das endgültige wird immer ausgeführt und nicht durch einen Thread-Abbruch unterbrochen, solange der Versuch tatsächlich eingegeben wurde, bevor der Thread-Abbruch erfolgte.
Das folgende Szenario wird schließlich nicht ausgeführt:
Asynchrone StackOverflowException.
Ab .NET 2.0 wird der Prozess durch einen Stapelüberlauf beendet. Das finally wird nicht ausgeführt, es sei denn, eine weitere Einschränkung wird angewendet, um das finally zu einer CER (Constrained Execution Region) zu machen. CERs sollten nicht im allgemeinen Benutzercode verwendet werden. Sie sollten nur verwendet werden, wenn es wichtig ist, dass der Bereinigungscode immer ausgeführt wird - nachdem der gesamte Prozess ohnehin beim Stapelüberlauf heruntergefahren wurde und alle verwalteten Objekte daher standardmäßig bereinigt werden. Daher sollte eine CER nur für Ressourcen relevant sein, die außerhalb des Prozesses zugewiesen werden, z. B. nicht verwaltete Handles.
In der Regel wird nicht verwalteter Code von einer verwalteten Klasse umbrochen, bevor er vom Benutzercode verwendet wird. Die verwaltete Wrapper-Klasse verwendet normalerweise ein SafeHandle, um das nicht verwaltete Handle zu verpacken. Der SafeHandle implementiert einen kritischen Finalizer und eine Release-Methode, die in einer CER ausgeführt wird, um die Ausführung des Bereinigungscodes zu gewährleisten. Aus diesem Grund sollten Sie keine CERs im gesamten Benutzercode sehen.
Die Tatsache, dass die Funktion schließlich nicht auf StackOverflowException ausgeführt wird, sollte sich nicht auf den Benutzercode auswirken, da der Prozess ohnehin beendet wird. Wenn Sie einen Randfall haben, in dem Sie eine nicht verwaltete Ressource außerhalb eines SafeHandle- oder CriticalFinalizerObject bereinigen müssen, verwenden Sie eine CER wie folgt. Beachten Sie jedoch, dass dies eine schlechte Praxis ist. Das nicht verwaltete Konzept sollte von Natur aus in eine verwaltete Klasse und geeignete SafeHandle (s) abstrahiert werden.
z.B,
quelle
FailFast
intern ein aus. Die einzige Möglichkeit, diese zu erfassen, besteht darin, das CLR-Laufzeithosting anzupassen . Beachten Sie, dass Ihr Punkt für einige andere asynchrone Ausnahmen weiterhin gültig ist.Es gibt eine sehr wichtige Ausnahme, die ich in keiner anderen Antwort erwähnt habe und die ich (nach 18-jähriger Programmierung in C #) nicht glauben kann, dass ich es nicht wusste.
Wenn Sie eine Ausnahme jeglicher Art in Ihrem
catch
Block auslösen oder auslösen (nicht nur seltsamStackOverflowExceptions
und solche Dinge) und Sie nicht den gesamtentry/catch/finally
Block in einem anderentry/catch
Block haben, wird Ihrfinally
Block nicht ausgeführt. Dies ist leicht zu demonstrieren - und wenn ich es nicht selbst gesehenfinally
hätte, hätte ich es nicht geglaubt, wenn man bedenkt, wie oft ich gelesen habe, dass es nur wirklich seltsame, winzige Eckfälle sind, die dazu führen können, dass ein Block nicht ausgeführt wird.Ich bin sicher, es gibt einen Grund dafür, aber es ist bizarr, dass es nicht bekannter ist. (Es wird hier zum Beispiel notiert , aber nirgendwo in dieser speziellen Frage.)
quelle
finally
Block ist einfach kein Haken für dencatch
Block.Mir ist klar, dass ich zu spät zur Party komme, aber in dem Szenario (das sich vom Beispiel des OP unterscheidet), in dem tatsächlich eine Ausnahme ausgelöst wird, werden MSDN-Zustände ( https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ) ausgelöst : "Wenn die Ausnahme nicht abgefangen wird, hängt die Ausführung des finally-Blocks davon ab, ob das Betriebssystem eine Ausnahme- Abwicklungsoperation auslöst."
Die Ausführung des finally-Blocks ist nur dann garantiert , wenn eine andere Funktion (z. B. Main) weiter oben im Aufrufstapel die Ausnahme abfängt. Dieses Detail ist normalerweise kein Problem, da alle C # -Programme in Laufzeitumgebungen (CLR und OS) auf den meisten Ressourcen ausgeführt werden, die ein Prozess beim Beenden besitzt (Dateihandles usw.). In einigen Fällen kann es jedoch entscheidend sein: Eine Datenbankoperation, die zur Hälfte ausgeführt wird und die Sie festschreiben möchten. entspannen; oder eine Remoteverbindung, die möglicherweise nicht automatisch vom Betriebssystem geschlossen wird und dann einen Server blockiert.
quelle
Ja. Das ist in der Tat der Hauptpunkt einer endgültigen Aussage. Sofern nicht etwas Katastrophales auftritt (nicht genügend Speicher, nicht angeschlossener Computer usw.), sollte die finally-Anweisung immer ausgeführt werden.
quelle
finally
Block zu umgehen , wenn diese Ausnahme nie abgefangen wird. Das hat mich überrascht ;-).Es wird auch nicht bei nicht erfassten Ausnahmen ausgelöst und in einem Thread ausgeführt, der in einem Windows-Dienst gehostet wird
Wird schließlich nicht ausgeführt, wenn in einem Thread, der in einem Windows-Dienst ausgeführt wird
quelle
Wird schließlich nicht ausgeführt, wenn Sie die Anwendung mit System.exit (0) verlassen. wie in
Das Ergebnis wäre nur: versuchen
quelle
c#
, aber das scheint zu seinJava
. Und außerdem ist in den meisten FällenSystem.exit()
ein Hinweis auf ein schlechtes Design :-)In 99% der Szenarien wird garantiert, dass der Code innerhalb des
finally
Blocks ausgeführt wird. Denken Sie jedoch an dieses Szenario: Sie haben einen Thread mit einemtry
->finally
Block (neincatch
) und Sie erhalten eine nicht behandelte Ausnahme innerhalb dieses Threads. In diesem Fall wird der Thread beendet und seinfinally
Block wird nicht ausgeführt (die Anwendung kann in diesem Fall weiter ausgeführt werden).Dieses Szenario ist ziemlich selten, aber es soll nur zeigen, dass die Antwort nicht IMMER "Ja" ist, sondern meistens "Ja" und manchmal, in seltenen Fällen, "Nein".
quelle
Der Hauptzweck von finally block besteht darin, alles auszuführen, was darin geschrieben ist. Es sollte nicht davon abhängen, was in try oder catch passiert. Mit System.Environment.Exit (1) wird die Anwendung jedoch beendet, ohne zur nächsten Codezeile zu wechseln.
quelle