Dieser Code ist Teil einer Anwendung, die aus einer mit ODBC verbundenen Datenbank liest und in diese schreibt. Es erstellt einen Datensatz in der Datenbank und prüft dann, ob ein Datensatz erfolgreich erstellt wurde, und kehrt dann zurück true
.
Mein Verständnis des Kontrollflusses ist wie folgt:
command.ExecuteNonQuery()
Es wird dokumentiert, dass ein InvalidOperationException
"ein Methodenaufruf für den aktuellen Status des Objekts ungültig ist" ausgelöst wird. Wenn dies passieren würde, würde die Ausführung des try
Blocks anhalten, der finally
Block würde ausgeführt und dann return false;
die unten ausgeführt.
Meine IDE behauptet jedoch, dass der return false;
Code nicht erreichbar ist. Und es scheint wahr zu sein, ich kann es entfernen und es kompiliert ohne Beschwerden. Für mich sieht es jedoch so aus, als gäbe es keinen Rückgabewert für den Codepfad, in dem die erwähnte Ausnahme ausgelöst wird.
private static bool createRecord(String table,
IDictionary<String,String> data,
System.Data.IDbConnection conn,
OdbcTransaction trans) {
[... some other code ...]
int returnValue = 0;
try {
command.CommandText = sb.ToString();
returnValue = command.ExecuteNonQuery();
return returnValue == 1;
} finally {
command.Dispose();
}
return false;
}
Was ist mein Verständnisfehler hier?
quelle
Dispose
explizit anrufen , sondern setzenusing
:using (var command = ...) {command.CommandText = sb.ToString(); return command.ExecuteNonQuery(); }
finally
Block bedeutet etwas anderes als Sie denken.Antworten:
Compiler-Warnung (Stufe 2) CS0162
Das heißt nur, dass der Compiler durch statische Analyse genug versteht, dass er nicht erreicht werden kann, und ihn vollständig aus der kompilierten IL auslässt (daher Ihre Warnung).
Hinweis : Sie können diese Tatsache selbst beweisen, indem Sie versuchen, mit dem Debugger auf den nicht erreichbaren Code zuzugreifen, oder einen IL Explorer verwenden
Das
finally
kann auf einer Ausnahme ausgeführt werden (obwohl dies beiseite gelegt wird), ändert nichts an der Tatsache (in diesem Fall), dass es sich immer noch um eine nicht erfasste Ausnahme handelt . Ergo wird der letztereturn
trotzdem nie getroffen.Wenn Sie den Code weiterhin auf dem letzten wollen
return
, ist Ihre einzige Option fangen die Ausnahme ;Wenn Sie dies nicht tun, lassen Sie es einfach so wie es ist und entfernen Sie das
return
.Beispiel
Um die Dokumentation zu zitieren
try-finally (C # -Referenz)
zuletzt
Wenn Sie etwas verwenden, das die
IDisposable
Schnittstelle unterstützt (die nicht verwaltete Ressourcen freigibt), können Sie sie in eineusing
Anweisung einschließen. Der Compiler generiert einentry {} finally {}
und ruftDispose()
das Objekt intern aufquelle
Falsch.
finally
schluckt die Ausnahme nicht. Es ehrt es und die Ausnahme wird wie gewohnt ausgelöst. Der Code wird erst in der Datei final ausgeführt, bevor der Block endet (mit oder ohne Ausnahme).Wenn Sie möchten, dass die Ausnahme verschluckt wird, sollten Sie einen
catch
Block ohne Nein verwendenthrow
.quelle
return false
da es stattdessen eine Ausnahme auslöst. @EhsanSajjadDie Warnung ist, weil Sie nicht verwendet haben
catch
und Ihre Methode im Grunde so geschrieben ist:Da Sie
finally
nur zur Entsorgung verwenden, besteht die bevorzugte Lösung darin,using
Muster zu verwenden:Das reicht aus, um sicherzustellen, was genannt
Dispose
wird. Es wird garantiert entweder nach erfolgreicher Ausführung des Codeblocks oder nach (vor) einemcatch
Ausfall im Aufrufstapel aufgerufen (übergeordnete Aufrufe sind ausgefallen, oder?).Wenn es nicht darum geht, zu entsorgen, dann
ist ausreichend, da Sie am Ende der Methode nie zurückkehren müssen
false
(diese Zeile ist nicht erforderlich). Ihre Methode gibt entweder das Ergebnis der Befehlsausführung zurück (true
oderfalse
) oder löst andernfalls eine Ausnahme aus .Ziehen Sie auch in Betracht, eigene Ausnahmen auszulösen, indem Sie erwartete Ausnahmen einschließen ( siehe InvalidOperationException-Konstruktor ):
Dies wird normalerweise verwendet, um dem Anrufer etwas Bedeutenderes (Nützlicheres) zu sagen, als eine verschachtelte Anrufausnahme aussagen würde.
Meistens interessieren Sie sich nicht wirklich für unbehandelte Ausnahmen. Manchmal müssen Sie sicherstellen, dass dies
finally
aufgerufen wird, auch wenn die Ausnahme nicht behandelt wird. In diesem Fall fangen Sie es einfach selbst und werfen es erneut (siehe diese Antwort ):quelle
Anscheinend suchen Sie nach so etwas:
Bitte beachten Sie, dass
finally
dies keine Ausnahme verschlucktquelle
Sie haben keinen
catch
Block, daher wird immer noch die Ausnahme ausgelöst, die die Rückgabe blockiert.Dies ist falsch, da der finally-Block ausgeführt würde und es dann eine nicht erfasste Ausnahme geben würde.
finally
Blöcke werden zur Bereinigung verwendet und erfassen die Ausnahme nicht. Die Ausnahme wird vor der Rückgabe ausgelöst, daher wird die Rückgabe nie erreicht, da zuvor eine Ausnahme ausgelöst wurde.Ihre IDE ist korrekt, dass sie niemals erreicht wird, da die Ausnahme ausgelöst wird. Nur
catch
Blöcke können Ausnahmen abfangen.Lesen aus der Dokumentation ,
Dies zeigt deutlich, dass das endgültige Ziel nicht darin besteht, die Ausnahme abzufangen, und Sie hätten Recht gehabt, wenn
catch
vor derfinally
Anweisung eine leere Anweisung vorhanden gewesen wäre .quelle
Wenn die Ausnahme ausgelöst wird, wird der Stapel abgewickelt (die Ausführung verlässt die Funktion), ohne dass ein Wert zurückgegeben wird, und jeder catch-Block in den Stapelrahmen über der Funktion fängt stattdessen die Ausnahme ab.
Daher
return false
wird nie ausgeführt.Versuchen Sie, manuell eine Ausnahme auszulösen, um den Kontrollfluss zu verstehen:
quelle
Auf Ihrem Code:
Dies ist der Fehler in Ihrer Logik, da der
finally
Block die Ausnahme nicht abfängt und niemals die letzte return-Anweisung erreicht.quelle
Die letzte Anweisung
return false
ist nicht erreichbar, da dem try-Block eincatch
Teil fehlt , der die Ausnahme behandeln würde. Daher wird die Ausnahme nach demfinally
Block erneut ausgelöst und die Ausführung erreicht nie die letzte Anweisung.quelle
Sie haben zwei Rückgabewege in Ihrem Code, von denen der zweite wegen des ersten nicht erreichbar ist. Die letzte Anweisung in Ihrem
try
Blockreturn returnValue == 1;
liefert Ihre normale Rendite, sodass Sie die nie erreichen könnenreturn false;
am Ende des Methodenblocks .FWIW, Reihenfolge der Prüfung in Bezug auf die
finally
Block lautet: Der Ausdruck, der den Rückgabewert im try-Block liefert, wird zuerst ausgewertet, dann wird der finally-Block ausgeführt und dann wird der berechnete Ausdruckswert zurückgegeben (innerhalb des try-Blocks).In Bezug auf den Ablauf bei Ausnahme ... ohne a
catch
wird derfinally
bei Ausnahme ausgeführt, bevor die Ausnahme dann aus der Methode entfernt wird. Es gibt keinen "Rückweg".quelle