2009-03-24 18 views
6

He estado ayudando a un colega a depurar algún comportamiento extraño en su código. El siguiente ejemplo ilustra esto:¿Por qué mi bloque finalmente no funciona en C#?

static void Main(string[] args) 
{ 
    string answer = Sample(); 
    Console.WriteLine(answer); 
} 

public static string Sample() 
{ 
    string returnValue = "abc"; 

    try 
    { 
     return returnValue; 
    } 

    catch (Exception) 
    { 
     throw; 
    } 

    finally 
    { 
     returnValue = "def"; 
    } 
} 

¿Qué devuelve este ejemplo?

¿Crees que debido al bloque finally, devuelve "def" pero de hecho, devuelve "abc"? He revisado el código y he confirmado que el bloque finalmente se invoca.

La verdadera respuesta es que no deberías escribir código como este en primer lugar, pero todavía estoy desconcertado en cuanto al comportamiento.

Editar: Para aclarar el flujo en función de algunas de las respuestas.

Al recorrer el código, finalmente se ejecuta antes de la devolución.

Duplicado de:What really happens in a try { return x; } finally { x = null; } statement?

Respuesta

3

Sí, el bloque finally se ejecuta después de que la función regrese, pero esto no importa. Recuerde que el valor devuelto se pasa por valor, por lo que se crea una nueva variable temporal en el momento del retorno, por lo tanto, el bloque finally no afecta en nada el valor de retorno real.Si quieres apoyar el comportamiento deseado se puede utilizar un parámetro de salida, así:

static void Main(string[] args) 
{ 
    string answer; 
    Sample(out answer); 
    Console.WriteLine(answer); 
} 

public static void Sample(out string answer) 
{ 

    try 
    { 
     answer = "abc"; 
     return; 
    } 

    catch (Exception) 
    { 
     throw; 
    } 

    finally 
    { 
     answer = "def"; 
    } 
} 

O, simplemente puede mover la instrucción de retorno fuera del bloque try, así:

static void Main(string[] args) 
{ 
    string answer = Sample(); 
    Console.WriteLine(answer); 
} 

public static string Sample() 
{ 
    string returnValue; 
    try 
    { 
     returnValue = "abc"; 
    } 

    catch (Exception) 
    { 
     throw; 
    } 

    finally 
    { 
     returnValue = "def"; 
    } 

    return returnValue; 
} 

Sin embargo, dado que el bloque finally siempre anulará el valor de retorno, este es un diseño cuestionable.

12

su "fin" de bloque es la asignación de un valor a returnValue y en realidad no devolver un valor. El "retorno" ya se ha producido antes de que el bloque finalmente cambie el valor y, por lo tanto, se devuelve "abc".

Si bien el código es confuso ya que lo que ha hecho no tiene sentido, lo que está haciendo es correcto.

+0

esto está mal..Si la declaración de devolución está dentro de un bloque try, el bloque finally, si existe, se ejecutará antes de que el control regrese al método de llamada. – TStamper

+0

TStamper: el valor de retorno se evalúa en la prueba mientras la variable sigue siendo "abc", luego finalmente se ejecuta y cambia la asignación de la variable pero NO se devuelve lo que ya se ha almacenado en caché. – Chuck

+0

cierto, pero la redacción es incorrecta. De lo que él está diciendo, el código no continúa ejecutándose en la función de Muestra – TStamper

0

No soy un experto, pero tendría que adivinar que esta función retorna, y luego invoca finalmente. Como return returnValue ya se ha ejecutado, realmente no importa el valor que devuelve returnValue en el bloque finally. Este comportamiento tiene sentido, porque es y se supone que ejecuta todo el bloque try antes del bloque finally, y la única forma en que puede hacer eso es si regresa de la función como debería.

3

El bloque finally ejecuta efectivamente después de la declaración return. Por lo tanto, ya devolvió el valor anterior de abc antes de ingresar a su bloque finally.

(esto no es exactamente la forma en que funciona bajo el capó, pero es lo suficientemente cerca para que el punto aquí)

2

encontrado this enlace Hace algún tiempo que se ocupa de esta misma pregunta. Él se toma la molestia de mostrar el código IL que lleva a casa exactamente lo que está sucediendo.

0

Si tiene curiosidad sobre lo que está pasando, entonces puede descargar e instalar Reflector. Es una herramienta fantástica para poner en su 'bolsa de trucos'. Te dirá lo que sucede debajo del capó.

0

Supongo que usted está determinando qué se devolverá (una referencia a la cadena "abc") en el punto donde está la declaración de devolución.

Por lo tanto, el hecho de que finalmente, después de establecer esa referencia para hacer referencia a una cadena diferente no tiene ningún efecto sobre el valor devuelto.

Cuestiones relacionadas