Добавляя к ответам, данным Марком Гравеллом и Джоном Скитом, важно отметить, что объекты и другие ссылочные типы ведут себя аналогично при возврате, но имеют некоторые различия.
Возвращаемое «Что» следует той же логике, что и простые типы:
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");
}
}
}
Возвращаемая ссылка уже была оценена до того, как локальной переменной была назначена новая ссылка в блоке finally.
Исполнение по сути:
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;
}
}
Разница в том, что все еще можно изменить изменяемые типы, используя свойства / методы объекта, что может привести к неожиданному поведению, если вы не будете осторожны.
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();
}
}
}
Второе, что следует учитывать при использовании try-return-finally, это то, что параметры, передаваемые «по ссылке», все еще можно изменить после возврата. Только возвращаемое значение было оценено и сохранено во временной переменной, ожидающей возврата, все остальные переменные по-прежнему модифицируются обычным способом. Контракт выходного параметра может даже остаться невыполненным до тех пор, пока не будет окончательно заблокирован этот путь.
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;
}
}
}
Как и любая другая конструкция потока, «try-return-finally» имеет свое место и может обеспечить более чистый вид кода, чем написание структуры, в которую он фактически компилируется. Но это нужно использовать осторожно, чтобы избежать ошибок Гоча.