Agregando a las respuestas dadas por Marc Gravell y Jon Skeet, es importante tener en cuenta que los objetos y otros tipos de referencia se comportan de manera similar cuando se devuelven pero tienen algunas diferencias.
el "qué" que es retornada sigue la misma lógica tipos simples:
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");
}
}
}
La referencia que se está devolviendo ya ha sido evaluado antes de que se le asigna la variable local una nueva referencia en el bloque finally.
La ejecución es esencialmente:
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;
}
}
La diferencia es aún sería posible modificar los tipos mutables utilizando las propiedades/métodos del objeto que puede dar lugar a comportamientos inesperados si no se tiene cuidado.
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();
}
}
}
Un segundo aspecto a considerar acerca de tratar de retorno fin es que los parámetros pasados "por referencia" todavía puede ser modificado después de la vuelta. Solo se ha evaluado el valor de retorno y se almacena en una variable temporal a la espera de ser devuelta, cualquier otra variable se sigue modificando de la manera normal. El contrato de un parámetro de salida puede incluso no cumplirse hasta que el bloque finalmente se bloquee de esta manera.
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;
}
}
}
Al igual que cualquier otro flujo construir "tratar de retorno, finalmente," tiene su lugar y puede permitir por mirar código más limpio que escribir la estructura que realidad compila a. Pero debe usarse con cuidado para evitar gotcha's.
¿No es esto exactamente lo que dice ocdedio: finalmente se ejecuta después del cálculo del valor de retorno y antes de realmente regresar de la función? – mmmmmmmm
Creo que la respuesta de Jon Skeet a continuación es más clara y precisa. –
"bloque manejado por excepción" Creo que este escenario no tiene nada que ver con las excepciones y el manejo de excepciones. Se trata de cómo .NET implementa la construcción finalmente _resource_guard. –