2010-07-09 62 views
48

Duplicar posible:
Will code in a Finally statement fire if I return a value in a Try block?¿El bloque C# "finally" SIEMPRE se ejecuta?

Consideremos el siguiente código de código C#. ¿El bloque "finalmente" se ejecuta?

public void DoesThisExecute() { 
    string ext = "xlsx"; 
    string message = string.Empty; 
    try { 
     switch (ext) { 
     case "xls": message = "Great choice!"; break; 
     case "csv": message = "Better choice!"; break; 
     case "exe": message = "Do not try to break me!"; break; 
     default: 
      message = "You will not win!"; 
      return; 
     } 
    } 
    catch (Exception) { 
     // Handle an exception. 
    } 
    finally { 
     MessageBox.Show(message); 
    } 
} 

Ha, después de terminar de escribir esto, me di cuenta de que podría haberlo probado yo mismo en Visual Studio. Sin embargo, ¡no dude en responder!

+4

No. Obtendrás un error de compilación. – Zano

+6

Lo único que no se compila es el punto y coma faltante después de declarar 'ext'. –

+1

@Zano - La faltante; fue un error tipográfico :) –

Respuesta

9
+38

No, no es así. http://thedailywtf.com/Articles/My-Tales.aspx –

+5

@IvanZlatanov La respuesta es correcta en el contexto de la pregunta, en la que el OP aparentemente quiere saber si finalmente se ejecutará incluso después de una declaración de devolución, sin importar cómo se encuentre. correcto que hay circunstancias bajo las cuales finalmente no se ejecutará. –

+0

Oh, te sorprenderías. Verifique esto: static int Main (string [] arguments) { try { return arguments [1000] .Length; } finalmente { System.Console.WriteLine ("¡nunca verá esto!"); } } –

0

Respuesta simple Sí. Pero hay algunas "excepciones" a la regla.

+2

¿viste la declaración 'return'? –

+6

@Gary: la declaración de devolución no es excusa. – EFraim

+2

Aún ingresará a la instrucción Finally independientemente de la declaración de devolución. –

1

Sí, finally siempre se ejecuta, ya sea o no el código del bloque finally provocará una excepción es una historia diferente.

4

De MSDN try-finally (C# Reference)

El bloque finally es útil para la limpieza de los recursos asignados en el bloque try , así como ejecutar cualquier código que debe ejecutar incluso si no es una excepción. El control siempre es pasado al bloque finally independientemente de de cómo sale el bloque try.

1

Sí, en circunstancias normales (como muchos otros han señalado).

El bloque finally es útil para la limpieza de los recursos asignados en el bloque try , así como ejecutar cualquier código que debe ejecutar incluso si no es una excepción. El control siempre es pasado al bloque finally independientemente de de cómo sale el bloque try.

Mientras que la captura se utiliza para manejar excepciones que se producen en un bloque de instrucciones , finalmente, se utiliza para garantizar un bloque declaración de código se ejecuta independientemente de cómo se sale del bloque try anterior.

http://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx

41

De MSDN C# especificación de la sentencia try.

Las instrucciones de un bloque finally siempre se ejecutan cuando el control deja una declaración try. Esto es cierto si la transferencia de control se produce como resultado de la ejecución normal, como resultado de la ejecución de un descanso, continuar, Goto, o la declaración de volver, o como resultado de propagar una excepción a cabo de la sentencia try .de la declaración try.

enlace Fuente:

http://msdn.microsoft.com/en-us/library/aa664733(v=VS.71).aspx

Hay los casos en que el bloque finally no se ejecutará.

  1. Environment.FailFast
  2. los execeptions Uncatchable
  3. de fallo de alimentación
+0

¡No lo sabía! :) –

+0

@Gary Willoughby, sabía que sí, pero no quería equivocarme, así que busqué en Google las especificaciones. – msarchet

+0

La especificación es incorrecta. Pruebe esto: static int Main (argumentos de cadena []) { try { return arguments [1000] .Length; } finalmente { System.Console.WriteLine ("¡nunca verá esto!"); } } –

68

No, no lo hace. Siempre se ejecutará siempre que la aplicación se esté ejecutando (excepto durante una excepción FastFail, MSDN link, como se indicó en otros). Se ejecutará cuando salga de la porción try/catch del bloque.

NO se ejecutará si la aplicación falla: se mata mediante un comando de proceso de eliminación, etc. Esto es muy importante, porque si escribe código que espera que se ejecute, como hacerlo manualmente, y si no sabio se comprometerá automáticamente, puede ejecutar en un escenario la aplicación aborta antes de que eso suceda. Honestamente, este es un escenario externo, pero es importante tomar nota en esas situaciones.

+4

Esto también incluye algunas Excepciones (las tres excepciones .net que no se pueden capturar), Application.FailFast o Power Outage (http://thedailywtf.com/Articles/My-Tales.aspx) –

+0

Y no lo hará ejecute si el código no se compila y ejecuta, ya que probablemente no lo hará, debido a la declaración de devolución. – DOK

+4

@DOK ¿Qué pasa con la Declaración de Devolución? –

1

La respuesta correcta es Sí.

Trate de depurar su programa y ponga un punto de interrupción y observe como el control sigue llegando al bloque finally.

1

No, no lo hace.

Sin embargo, hay una sola manera de evitarlo, que es Environment.FailFast(). Ver http://msdn.microsoft.com/de-de/library/ms131100.aspx. En todos los demás casos, se garantiza que los finalizadores se ejecutan ;-)

El método FailFast escribe la cadena del mensaje a la registro de eventos de aplicación de Windows, crea un volcado de la aplicación , y luego termina la corriente proceso. La cadena del mensaje es también incluida en el informe de errores a Microsoft.

utilizar el método de FailFast en lugar del método Salir para finalizar su aplicación si el estado de su solicitud está dañado sin posibilidad de reparación, y ejecutar try/finally bloques y finalizadores voluntad recursos de programas corruptos de su aplicación.

+1

Cualquier cosa que termine el proceso directamente en lugar de dejar que se cierre suavemente evitará que 'finalmente' se ejecute. –

29

No es totalmente cierto que finally siempre se ejecutará.Ver this answer de Haacked:

dos posibilidades:

  • StackOverflowException
  • ExecutingEngineException

El bloque finally no se ejecutará cuando hay una StackOverflowException ya que no hay espacio en la apilar hasta incluso ejecutivo Ute más código Tampoco se llamará a cuando existe una excepción ExecutingEngineException, que es muy rara.

De hecho, para cualquier tipo de excepción asíncrona (como StackOverflowException, OutOfMemoryException, ThreadAbortException) la ejecución de un bloque finally no está garantizada.

Sin embargo, estas excepciones son excepciones de las que generalmente no puede recuperarse, y en la mayoría de los casos su proceso se cerrará de todos modos.

De hecho, también hay al menos otro caso en el que finally no se ejecuta como se describe por Brian Rasmussen en un momento deleted question:

El otro caso soy consciente de que es si un finalizador se emite una excepción . En ese caso , el proceso finaliza también en , por lo que la garantía no se aplica.

El código siguiente ilustra el problema

static void Main(string[] args) { 
    try { 
     DisposableType d = new DisposableType(); 
     d.Dispose(); 
     d = null; 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
    } catch { 
     Console.WriteLine("catch"); 
    } finally { 
     Console.WriteLine("finally"); 
    } 
} 

public class DisposableType : IDisposable { 
    public void Dispose() { 
    } 

    ~DisposableType() { 
     throw new NotImplementedException(); 
    } 
} 

Un try fiable/catch/finally tendrá que utilizar Constrained Execution Regions (CER). Un example se proporciona por MSDN:

[StructLayout(LayoutKind.Sequential)] 
struct MyStruct 
{ 
    public IntPtr m_outputHandle; 
} 

sealed class MySafeHandle : SafeHandle 
{ 
    // Called by P/Invoke when returning SafeHandles 
    public MySafeHandle() 
     : base(IntPtr.Zero, true) 
    { 
    } 

    public MySafeHandle AllocateHandle() 
    { 
     // Allocate SafeHandle first to avoid failure later. 
     MySafeHandle sh = new MySafeHandle(); 

     RuntimeHelpers.PrepareConstrainedRegions(); 
     try { } 
     finally 
     { 
      MyStruct myStruct = new MyStruct(); 
      NativeAllocateHandle(ref myStruct); 
      sh.SetHandle(myStruct.m_outputHandle); 
     } 

     return sh; 
    } 
} 

una excelente fuente de información es el siguiente artículo:

Reliability Best Practices

+0

¿Podría hacer una copia de seguridad de lo que dijo sobre 'ThreadAbortException' que no desencadena' finally'? –

+0

De acuerdo, estoy bastante seguro de que ThreadAbortException intenta ejecutar el bloque finally. Favorece el bloqueo final sobre abortar el hilo, por lo que este último está menos garantizado que el primero. – David

+0

@Steven Sudit, @David: Lo siento, probablemente no tenía razón sobre esto. De alguna manera tuve esto en la parte posterior de mi cabeza, pero MSDN dice claramente que 'finally' se ejecutará. –

2

El bloque finally se ejecutará, justo entre estas líneas:

message = "You will not win!"; 
return; 
Cuestiones relacionadas