Nein - auf IL-Ebene können Sie nicht aus einem Block mit Ausnahmebehandlung zurückkehren. Es speichert es im Wesentlichen in einer Variablen und kehrt danach zurück
dh ähnlich wie:
int tmp;
try {
tmp = ...
} finally {
...
}
return tmp;
Zum Beispiel (mit Reflektor):
static int Test() {
try {
return SomeNumber();
} finally {
Foo();
}
}
kompiliert zu:
.method private hidebysig static int32 Test() cil managed
{
.maxstack 1
.locals init (
[0] int32 CS$1$0000)
L_0000: call int32 Program::SomeNumber()
L_0005: stloc.0
L_0006: leave.s L_000e
L_0008: call void Program::Foo()
L_000d: endfinally
L_000e: ldloc.0
L_000f: ret
.try L_0000 to L_0008 finally handler L_0008 to L_000e
}
Dies deklariert im Grunde eine lokale Variable ( CS$1$0000
), platziert den Wert in der Variablen (innerhalb des behandelten Blocks) und lädt nach dem Verlassen des Blocks die Variable und gibt sie dann zurück. Reflektor macht dies wie folgt:
private static int Test()
{
int CS$1$0000;
try
{
CS$1$0000 = SomeNumber();
}
finally
{
Foo();
}
return CS$1$0000;
}
Die finally-Anweisung wird ausgeführt, der Rückgabewert wird jedoch nicht beeinflusst. Die Ausführungsreihenfolge lautet:
Hier ist ein kurzes Programm zur Demonstration:
Dies gibt "try" aus (weil das zurückgegeben wird) und dann "finally", weil dies der neue Wert von x ist.
Wenn wir einen Verweis auf ein veränderbares Objekt (z. B. einen StringBuilder) zurückgeben, werden alle Änderungen, die am Objekt im finally-Block vorgenommen wurden, bei der Rückgabe sichtbar - dies hat keinen Einfluss auf den Rückgabewert selbst (der nur ein Wert ist) Referenz).
quelle
return
Anweisung aus und dieser Wert wird zurückgegeben. Der Ausdruck wird nicht ausgewertet, da die Kontrolle die Methode verlässt.Die finally-Klausel wird nach der return-Anweisung ausgeführt, jedoch bevor sie tatsächlich von der Funktion zurückkehrt. Es hat wenig mit Thread-Sicherheit zu tun, denke ich. Es ist kein Hack - das wird garantiert immer ausgeführt, egal was Sie in Ihrem Try-Block oder Ihrem Catch-Block tun.
quelle
Zusätzlich zu den Antworten von Marc Gravell und Jon Skeet ist es wichtig zu beachten, dass sich Objekte und andere Referenztypen bei der Rückgabe ähnlich verhalten, jedoch einige Unterschiede aufweisen.
Das zurückgegebene "Was" folgt der gleichen Logik wie einfache Typen:
Die zurückgegebene Referenz wurde bereits ausgewertet, bevor der lokalen Variablen im finally-Block eine neue Referenz zugewiesen wurde.
Die Ausführung ist im Wesentlichen:
Der Unterschied besteht darin, dass es weiterhin möglich ist, veränderbare Typen mithilfe der Eigenschaften / Methoden des Objekts zu ändern, was zu unerwartetem Verhalten führen kann, wenn Sie nicht vorsichtig sind.
Eine zweite Sache, die bei try-return-finally zu beachten ist, ist, dass Parameter, die "als Referenz" übergeben werden, nach der Rückgabe noch geändert werden können. Nur der Rückgabewert wurde ausgewertet und in einer temporären Variablen gespeichert, die darauf wartet, zurückgegeben zu werden. Alle anderen Variablen werden weiterhin auf normale Weise geändert. Der Vertrag eines out-Parameters kann sogar bis zur endgültigen Blockierung auf diese Weise unerfüllt bleiben.
Wie jedes andere Flusskonstrukt hat "try-return-finally" seinen Platz und kann saubereren Code ermöglichen, als die Struktur zu schreiben, in die es tatsächlich kompiliert wird. Aber es muss vorsichtig verwendet werden, um Gotchas zu vermeiden.
quelle
Wenn
x
es sich um eine lokale Variable handelt, sehe ich den Punkt nicht, da erx
beim Beenden der Methode ohnehin effektiv auf null gesetzt wird und der Wert des Rückgabewerts nicht null ist (da er vor dem Aufruf zum Setzen in das Register gestellt wurdex
zu null).Ich kann dies nur sehen, wenn Sie die Änderung des Wertes eines Feldes bei der Rückgabe (und nach der Bestimmung des Rückgabewerts) garantieren möchten.
quelle