Ich habe kein Problem; Ich bin nur Neugierig. Stellen Sie sich folgendes Szenario vor:
foreach (var foo in list)
{
try
{
//Some code
}
catch (Exception)
{
//Some more code
}
finally
{
continue;
}
}
Dies wird nicht kompiliert, da es den Compilerfehler CS0157 auslöst :
Die Kontrolle kann den Text einer finally-Klausel nicht verlassen
Warum?
continue;
infinally
block? ist es nicht dasselbe wiecontinue;
nach demtry -- catch
Block?finally/continue
eine Einschränkung des C # -Compilers ist :-) Ich bin auch neugierig auf den Grund dieser Einschränkung.br
Familie der Zweiganweisungen kann dies nicht erreichen.Antworten:
finally
Blöcke werden ausgeführt, unabhängig davon, ob eine Ausnahme ausgelöst wird oder nicht. Was zum Teufel würdecontinue
tun, wenn eine Ausnahme ausgelöst wird ? Sie können die Ausführung der Schleife nicht fortsetzen, da eine nicht erfasste Ausnahme die Steuerung an eine andere Funktion überträgt.Selbst wenn keine Ausnahme ausgelöst wird,
finally
wird sie ausgeführt, wenn andere Steuerungsübertragungsanweisungen innerhalb des try / catch-Blocks ausgeführt werdenreturn
, z. B. a, was das gleiche Problem mit sich bringt.Kurz gesagt, mit der Semantik macht
finally
es keinen Sinn, die Kontrolle von innerhalb einesfinally
Blocks nach außen zu übertragen.Dies mit einer alternativen Semantik zu unterstützen, wäre eher verwirrend als hilfreich, da es einfache Problemumgehungen gibt, die das beabsichtigte Verhalten klarer machen. Sie erhalten also einen Fehler und müssen über Ihr Problem richtig nachdenken. Es ist die allgemeine Idee "Wirf dich in die Grube des Erfolgs", die in C # weitergeht.
Wenn Sie Ausnahmen ignorieren möchten (meistens ist dies eine schlechte Idee) und die Schleife weiter ausführen möchten, verwenden Sie einen catch all-Block:
Wenn Sie
continue
nur dann möchten, wenn keine nicht erfassten Ausnahmen ausgelöst werden, setzen Sie sie einfachcontinue
außerhalb des Try-Blocks.quelle
continue
in einemfinally
Block in Ordnung, wenn nur eine imfinally
Block definierte lokale Schleife fortgesetzt wird . In der Frage wird jedoch versucht, eine "äußere" Schleife fortzusetzen. Ähnliche Anweisungen, die Sie nicht in einemfinally
Block haben könnenreturn
, sindbreak
(wenn Sie aus dem Block ausbrechen) undgoto
(wenn Sie zu einem Label außerhalb desfinally
Blocks gehen). Eine verwandte Java-Diskussion finden Sie unter Zurückkehren von einem finally-Block in Java .Hier ist eine zuverlässige Quelle:
Es stammt aus MSDN, 8.9.2 Die continue-Anweisung .
Die Dokumentation sagt, dass:
Es ist von hier 8.10 Die try-Anweisung .
quelle
Sie mögen denken, dass es Sinn macht, aber es macht eigentlich keinen Sinn .
Was beabsichtigen Sie, eine Pause einzulegen oder fortzufahren, wenn eine Ausnahme ausgelöst wird? Das C # -Compilerteam möchte keine eigene Entscheidung treffen, indem es
break
oder annimmtcontinue
. Stattdessen beschlossen sie, sich darüber zu beschweren, dass die Entwicklersituation nicht eindeutig ist, um die Kontrolle zu übertragenfinally block
.Es ist also die Aufgabe des Entwicklers, klar anzugeben, was er vorhat, anstatt dass der Compiler etwas anderes annimmt.
Ich hoffe du verstehst warum das nicht kompiliert wird!
quelle
finally
gäbe, würde der Ausführungspfad nach einer Anweisung davon abhängen, ob dercatch
über eine Ausnahme beendet wurde, und es gibt keinen Mechanismus, um zu sagen, wie dies mit a interagieren sollcontinue
. Ich mag Ihr Beispiel jedoch, weil es ein noch größeres Problem zeigt.Wie andere gesagt haben, sich aber auf Ausnahmen konzentrieren, geht es wirklich um die mehrdeutige Behandlung der Übertragung von Kontrolle.
In Ihrem Kopf denken Sie wahrscheinlich an ein Szenario wie dieses:
Theoretisch können Sie den Kontrollfluss verfolgen und sagen, ja, das ist "ok". Es wird keine Ausnahme ausgelöst, keine Kontrolle übertragen. Die C # -Sprachendesigner hatten jedoch andere Probleme.
Die geworfene Ausnahme
Der gefürchtete Goto
Die Rückkehr
Die Trennung
Zusammenfassend lässt sich sagen, dass es zwar eine geringfügige Möglichkeit gibt, a
continue
in Situationen zu verwenden, in denen die Kontrolle nicht übertragen wird, aber in vielen Fällen (Mehrheit?) Ausnahmen oderreturn
Blockierungen auftreten. Die Sprachdesigner waren der Meinung, dass dies zu vieldeutig und (wahrscheinlich) unmöglich wäre, um bei der Kompilierung sicherzustellen, dass Ihrecontinue
verwendet wird nur in Fällen , in denen der Kontrollfluss nicht übertragen wird.quelle
Im Allgemeinen
continue
macht es keinen Sinn, wenn es imfinally
Block verwendet wird. Schau dir das an:quelle
continue
macht außerhalb der Schleifenanweisung keinen Sinn, bedeutet aber nicht, dass sie nicht unterstützt wird.item
kann Datei sein, Lesen fehlgeschlagen ->finally
schließt die Datei.continue
verhindert den Rest der Verarbeitung.Nun, ich denke nicht.
Wenn Sie buchstäblich haben,
catch(Exception)
dann brauchen Sie nicht das endgültige (und wahrscheinlich nicht einmal dascontinue
).catch(SomeException)
Was sollte passieren, wenn eine Ausnahme nicht abgefangen wird, wenn Sie realistischer sind? Siecontinue
möchten einen Weg gehen, die Ausnahme einen anderen.quelle
finally
wenn Sie habencatch
. Es wird häufig zum zuverlässigen Schließen von Ressourcen verwendet.return
Aussage in Ihremtry
odercatch
Blöcken haben. Was tun wir jetzt? Zurückkehren oder die Schleife fortsetzen? (Und wenn wir fortfahren, was ist, wenn es das letzte Element ist, das iteriert? Dann fahren wir einfach außerhalb von fortforeach
und die Rückgabe erfolgt nie?) BEARBEITEN: Oder sogargoto
zu einem Label außerhalb der Schleife, so ziemlich jeder Aktion, die die Kontrolle außerhalb derforeach
Schleife überträgt .return
s innerhalb des Blocks. Normalerweise wird die Ausführung jedoch nach dem Allheilmittel fortgesetzt.Sie können den Körper eines endgültigen Blocks nicht verlassen. Dies umfasst die Schlüsselwörter break, return und in Ihrem Fall continue.
quelle
Der
finally
Block kann mit einer Ausnahme ausgeführt werden, die darauf wartet, erneut ausgelöst zu werden. Es wäre nicht wirklich sinnvoll, den Block verlassen zu können (durch acontinue
oder irgendetwas anderes) verlassen zu können, ohne die Ausnahme erneut auszulösen.Wenn Sie Ihre Schleife fortsetzen möchten, brauchen Sie nicht die finally-Anweisung: Fangen Sie einfach die Ausnahme ab und werfen Sie sie nicht erneut.
quelle
finally
Läuft, ob eine nicht erfasste Ausnahme ausgelöst wird oder nicht. Andere haben bereits erklärt, warum diescontinue
unlogisch ist, aber hier ist eine Alternative, die dem Geist dessen folgt, wonach dieser Code zu fragen scheint. Grundsätzlichfinally { continue; }
heißt es:(1) könnte durch Platzieren
continue
am Ende eines jeden erfüllt werdencatch
, und (2) könnte durch Speichern nicht erfasster Ausnahmen, die später geworfen werden sollen, befriedigt werden. Sie könnten es so schreiben:Eigentlich
finally
hätte auch im dritten Fall ausgeführt, wo es überhaupt keine Ausnahmen gab, gefangen oder nicht gefangen. Wenn das gewünscht wäre, könnten Sie natürlich einfach einen einzelnencontinue
nach dem Try-Catch-Block platzieren, anstatt in jedemcatch
.quelle
Technisch gesehen ist dies eine Einschränkung der zugrunde liegenden CIL. Aus der Sprachspezifikation :
und
Auf der Dokumentseite für die
br
Anweisung :Dieser letzte gilt für wahr alle Zweigbefehle, einschließlich
beq
,brfalse
usw.quelle
Die Designer der Sprache wollten (oder konnten) einfach nicht begründen, dass die Semantik eines endgültigen Blocks durch eine Steuerungsübertragung beendet wird.
Ein Problem oder vielleicht das Hauptproblem ist, dass die
finally
Block als Teil einer nicht lokalen Steuerübertragung (Ausnahmeverarbeitung) ausgeführt wird. Das Ziel dieser Steuerübertragung ist nicht die umschließende Schleife. Die Ausnahmeverarbeitung bricht die Schleife ab und wickelt sich weiter ab.Wenn wir eine Kontrollübertragung aus dem haben
finally
Bereinigungsblock haben, wird die ursprüngliche Kontrollübertragung "entführt". Es wird abgebrochen und die Kontrolle geht woanders hin.Die Semantik kann ausgearbeitet werden. Andere Sprachen haben es.
Die Designer von C # haben beschlossen, statische, "goto-ähnliche" Steuerübertragungen einfach nicht zuzulassen, wodurch die Dinge etwas vereinfacht wurden.
Selbst wenn Sie dies tun, wird die Frage, was passiert, wenn eine dynamische Übertragung von a initiiert wird, nicht gelöst
finally
: Was wenn der finally-Block eine Funktion aufruft und diese Funktion auslöst? Die ursprüngliche Ausnahmeverarbeitung wird dann "entführt".Wenn Sie die Semantik dieser zweiten Form der Entführung herausarbeiten, gibt es keinen Grund, den ersten Typ zu verbannen. Sie sind wirklich dasselbe: Eine Kontrollübertragung ist eine Kontrollübertragung, unabhängig davon, ob sie denselben lexikalischen Umfang hat oder nicht.
quelle
finally
per Definition muss sofort durch die Fortsetzung der Übertragung folgen, die es ausgelöst (eine abgefangene Ausnahme,return
usw.). Es wäre leicht, "goto-ähnliche" Übertragungen innerhalb von zuzulassenfinally
(welche Sprachen tun dies übrigens?), Aber dies würde bedeuten, dass diestry { return } finally { ... }
möglicherweise nicht zurückkehrt , was völlig unerwartet ist. Wennfinally
eine Funktion aufgerufen wird, die ausgelöst wird, ist dies nicht wirklich dasselbe, da wir bereits erwarten, dass jederzeit Ausnahmen auftreten und den normalen Ablauf unterbrechen können.finally
insofern dasselbe, als sie zu einem unerwarteten und unlogischen Programmfluss führen kann. Der einzige Unterschied besteht darin, dass die Sprachdesigner nicht in der Lage sind, alle Programme abzulehnen, bei denen ein endgültiger Block eine nicht behandelte Ausnahme auslösen könnte, sondern stattdessen zulassen, dass solche Programme kompiliert werden, und hoffen, dass das Programm alle Konsequenzen akzeptieren kann, die sich aus dem Abbruch der früheren Ausnahmefreigabe ergeben können Reihenfolge.finally
oder nicht. Nach der Logik des letzten Absatzes von Kaz sollten Funktionen auch frei sein, den Fluss im Bereich ihres Anrufers übercontinue
usw. zu beeinflussen, da sie dies aus Ausnahmen tun dürfen. Dies ist aber natürlich nicht erlaubt; Ausnahmen sind die einzige Ausnahme von dieser Regel, daher der Name "Ausnahme" (oder "Interrupt").finally
Blocks auftritt , kann dagegen verstoßen. Wirklich eine schlimme Situation, die meiner Meinung nach hätte gelöst werden müssen, indemfinally
Blöcke mindestens über ausstehende Ausnahmen informiert wurden, damit sie zusammengesetzte Ausnahmeobjekte erstellen können.