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:
class Test {
public static Exception AnException() {
Exception ex = new Exception("Me");
try {
return ex;
} finally {
// Reference unchanged, Local variable changed
ex = new Exception("Not Me");
}
}
}
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:
class Test {
public static Exception AnException() {
Exception ex = new Exception("Me");
Exception CS$1$0000 = null;
try {
CS$1$0000 = ex;
} finally {
// Reference unchanged, Local variable changed
ex = new Exception("Not Me");
}
return CS$1$0000;
}
}
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.
class Test2 {
public static System.IO.MemoryStream BadStream(byte[] buffer) {
System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer);
try {
return ms;
} finally {
// Reference unchanged, Referenced Object changed
ms.Dispose();
}
}
}
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.
class ByRefTests {
public static int One(out int i) {
try {
i = 1;
return i;
} finally {
// Return value unchanged, Store new value referenced variable
i = 1000;
}
}
public static int Two(ref int i) {
try {
i = 2;
return i;
} finally {
// Return value unchanged, Store new value referenced variable
i = 2000;
}
}
public static int Three(out int i) {
try {
return 3;
} finally {
// This is not a compile error!
// Return value unchanged, Store new value referenced variable
i = 3000;
}
}
}
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.