En C #, ¿el bloque Finally se ejecutará en un try, catch, finalmente si se lanza una excepción no controlada?

Otra pregunta de la entrevista que esperaba una respuesta verdadera / falsa y no estaba muy seguro.

Duplicar

  • En .NET, ¿qué pasa si algo falla en el bloque catch, finalmente siempre se llamará?
  • ¿Siempre se ejecuta un locking final?
  • Condiciones cuando finalmente no se ejecuta en un .net try … bloque final
  • ¿Describirá el código en una instrucción Finally si devuelvo un valor en un bloque Try?

finally se ejecuta la mayor parte del tiempo . Es casi todos los casos. Por ejemplo, si se lanza una excepción async (como StackOverflowException , OutOfMemoryException , ThreadAbortException ) en la OutOfMemoryException , finally no se garantiza la ejecución. Esta es la razón por la cual existen regiones de ejecución restringidas para escribir código altamente confiable.

A los fines de la entrevista, espero que la respuesta a esta pregunta sea falsa (¡no garantizaré nada! ¡Puede que el entrevistador no lo sepa!).

Generalmente, el bloque finally está garantizado para ejecutarse.

Sin embargo, unos pocos casos fuerzan el cierre de CLR en caso de error. En esos casos, el bloque finally no se ejecuta.

Un ejemplo de esto es en presencia de una excepción de StackOverflow.

Por ejemplo, en el código siguiente, el bloque finally no se ejecuta.

 static void Main(string[] args) { try { Foo(1); } catch { Console.WriteLine("catch"); } finally { Console.WriteLine("finally"); } } public static int Foo(int i) { return Foo(i + 1); } 

El otro caso que conozco es si un finalizador arroja una excepción. En ese caso, el proceso finaliza inmediatamente también, y por lo tanto la garantía no se aplica.

El código a continuación 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(); } } 

En ambos casos, el proceso finaliza antes de catch y finally .

Admitiré que los ejemplos son muy artificiales, pero están hechos para ilustrar el punto.

Afortunadamente, ninguno de los dos ocurre muy a menudo.

Directamente desde MSDN:

El bloque finally es útil para limpiar cualquier recurso asignado en el bloque try. El control siempre pasa al bloque finally independientemente de cómo salga el bloque try.

Mientras que catch se utiliza para manejar excepciones que se producen en un bloque de instrucciones, finalmente se utiliza para garantizar que un bloque de instrucciones se ejecute independientemente de cómo se salga del bloque try anterior.

http://msdn.microsoft.com/en-us/library/zwc8s4fz(VS.71,loband).aspx

Sí, finalmente siempre se ejecuta.

No es totalmente cierto que finalmente siempre se ejecutará. Ver esta respuesta de Haacked :

Dos posibilidades:

  • StackOverflowException
  • ExecutingEngineException

El bloque finally no se ejecutará cuando exista StackOverflowException ya que no hay espacio en la stack para ejecutar más código. Tampoco se llamará cuando exista ExecutingEngineException, lo cual es muy raro.

Sin embargo, estas dos excepciones son una excepción de la que no puede recuperarse, por lo que básicamente su proceso se cerrará de todos modos.

Como lo menciona Mehrdad, un bash / captura / finalmente confiable tendrá que usar Regiones de Ejecución Restringidas (CER) . Un ejemplo es proporcionado 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; } } 

En general, el bloque finally se ejecuta siempre independientemente de si se lanza una excepción o no y si se maneja o no una excepción.

Hay un par de excepciones (ver otras respuestas para más detalles).

‘Finalmente’ se ejecuta independientemente de si se lanza una excepción o no.

Es un buen lugar para cerrar cualquier conexión abierta. Una ejecución exitosa o fallida, aún puede administrar sus conexiones o abrir archivos.

Finalmente sucederá cada vez para ese bloque try catch

Finalmente se garantiza que el bloque se ejecutará en cualquier caso.

Finalmente siempre se ejecuta. No depende de cómo funciona el bloque try. Si tienes que hacer un trabajo extra para try y cath, es mejor ponerlo finalmente en block. Entonces puede garantizar que siempre se ejecuta.