Estoy revisando un código para un amigo y digo que estaba usando una declaración de devolución dentro de un bloque try-finally. ¿El código en la sección Finalmente todavía se activa aunque el resto del bloque try no?
Ejemplo:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn't seem to get executed
}
finally
{
//code in question
}
}
c#
.net
exception-handling
try-catch
JamesEggers
fuente
fuente
StackOverflowException
,ExecutionEngineException
son algunos de ellos. Y como no se pueden manejar,finally
no se ejecutarán.try
bloque. Nada sobre abortos abruptos del programa.try
bloque es unareturn
declaración. (La segunda declaración de ese bloque es inalcanzable y generará una advertencia.)Respuestas:
Respuesta simple: sí.
fuente
finally
bloque se ejecutará.Normalmente si. La última sección está garantizada para ejecutar lo que suceda, incluidas las excepciones o la declaración de devolución. Una excepción a esta regla es una excepción asincrónica que ocurre en el hilo (
OutOfMemoryException
,StackOverflowException
).Para obtener más información sobre las excepciones asíncronas y el código confiable en esas situaciones, lea sobre las regiones de ejecución restringidas .
fuente
Aquí hay una pequeña prueba:
El resultado es:
fuente
WriteLine
se realiza realmente el resultado de la llamada al método. En este caso, lareturn
llamada establece el resultado de los métodos, finalmente escribe en la consola, antes de que salga el método. Luego,WriteLine
en el método Principal escupe el texto de la llamada de retorno.Citando desde MSDN
fuente
finally
de hecho, no garantiza nada incluso para programas perfectamente ordinarios (lo que resultó en esta excepción).En general sí, finalmente se ejecutará.
Para los siguientes tres escenarios, el SIEMPRE se ejecutará SIEMPRE :
Esto incluye excepciones compatibles con CLS que se derivan de System.Exception y excepciones no compatibles con CLS, que no se derivan de System.Exception. RuntimeWrappedException ajusta automáticamente las excepciones que no cumplen con CLS. C # no puede lanzar excepciones de reclamos que no sean de CLS, pero sí pueden lenguajes como C ++. C # podría estar llamando a un código escrito en un lenguaje que puede generar excepciones no compatibles con CLS.
A partir de .NET 2.0, una ThreadAbortException ya no impedirá que finalmente se ejecute. ThreadAbortException ahora se iza antes o después de finalmente. El finalmente siempre se ejecutará y no será interrumpido por un aborto de hilo, siempre que el intento se haya introducido antes de que ocurriera el aborto de hilo.
El siguiente escenario, el finalmente no se ejecutará:
StackOverflowException asíncrono.
A partir de .NET 2.0, un desbordamiento de la pila hará que el proceso finalice. Finalmente, no se ejecutará, a menos que se aplique una restricción adicional para que finalmente sea un CER (Región de ejecución restringida). Los CER no deben usarse en el código de usuario general. Solo deben usarse donde sea crítico que el código de limpieza siempre se ejecute, ya que de todos modos el proceso se está cerrando en el desbordamiento de la pila y, por lo tanto, todos los objetos administrados se limpiarán de manera predeterminada. Por lo tanto, el único lugar donde un CER debería ser relevante es para los recursos que se asignan fuera del proceso, por ejemplo, los identificadores no administrados.
Por lo general, el código no administrado lo envuelve alguna clase administrada antes de ser consumido por el código de usuario. La clase de contenedor administrado generalmente utilizará un SafeHandle para ajustar el identificador no administrado. SafeHandle implementa un finalizador crítico y un método de lanzamiento que se ejecuta en un CER para garantizar la ejecución del código de limpieza. Por este motivo, no debería ver CERs llenos de código de usuario completo.
Entonces, el hecho de que finalmente no se ejecute en StackOverflowException no debería tener ningún efecto en el código del usuario, ya que el proceso finalizará de todos modos. Si tiene algún caso límite en el que necesita limpiar algún recurso no administrado, fuera de SafeHandle o CriticalFinalizerObject, utilice un CER de la siguiente manera; pero tenga en cuenta que esta es una mala práctica: el concepto no administrado debe abstraerse a una (s) clase (s) administrada (s) y SafeHandle (s) apropiados por diseño.
p.ej,
fuente
FailFast
interno. La única forma en que pude atraparlos fue personalizando el alojamiento de tiempo de ejecución CLR . Tenga en cuenta que su punto sigue siendo válido para algunas otras excepciones asincrónicas.Hay una excepción muy importante a esto que no he visto mencionado en ninguna otra respuesta y que (después de programar en C # durante 18 años) no puedo creer que no lo supiera.
Si lanza o activa una excepción de cualquier tipo dentro de su
catch
bloque (no solo extrañosStackOverflowExceptions
y cosas de ese tipo), y no tiene todo eltry/catch/finally
bloque dentro de otrotry/catch
bloque, sufinally
bloque no se ejecutará. Esto se demuestra fácilmente, y si no lo hubiera visto yo mismo, dada la frecuencia con la que he leído que solo son casos de esquina muy extraños y pequeños que pueden hacer que unfinally
bloque no se ejecute, no lo habría creído.Estoy seguro de que hay una razón para esto, pero es extraño que no se conozca más ampliamente. (Se nota aquí, por ejemplo, pero no en ninguna parte de esta pregunta en particular).
fuente
finally
bloque simplemente no es una trampa para elcatch
bloque.Me doy cuenta de que llego tarde a la fiesta, pero en el escenario (que difiere del ejemplo del OP) donde de hecho se lanza una excepción a los estados de MSDN ( https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ): "Si no se detecta la excepción, la ejecución del bloque finalmente depende de si el sistema operativo elige activar una operación de desenrollado de excepción".
El último bloque solo se garantiza para ejecutarse si alguna otra función (como Principal) más arriba en la pila de llamadas detecta la excepción. Este detalle generalmente no es un problema porque todos los programas C # de entornos de tiempo de ejecución (CLR y OS) se ejecutan en la mayoría de los recursos libres que posee un proceso cuando sale (identificadores de archivos, etc.). Sin embargo, en algunos casos puede ser crucial: una operación de base de datos a mitad de camino en la que desea comprometerse relajarse; o alguna conexión remota que puede no ser cerrada automáticamente por el sistema operativo y luego bloquea un servidor.
fuente
Si. De hecho, ese es el punto principal de una declaración final. A menos que ocurra algo catastrófico (sin memoria, computadora desconectada, etc.), la declaración final siempre debe ejecutarse.
fuente
finally
bloque si esa excepción nunca se detecta. Eso me tomó por sorpresa ;-).Tampoco se activará en una excepción no capturada y se ejecutará en un hilo alojado en un Servicio de Windows
Finalmente no se ejecuta cuando se está ejecutando un subproceso en un servicio de Windows
fuente
finalmente no se ejecutará en caso de que salga de la aplicación usando System.exit (0); como en
el resultado sería solo: intente
fuente
c#
, pero parece serJava
. Y además de eso, en la mayoría de los casosSystem.exit()
es un indicio de un mal diseño :-)En el 99% de los escenarios se garantizará que el código dentro del
finally
bloque se ejecutará, sin embargo, piense en este escenario: tiene un hilo que tiene un bloquetry
->finally
(nocatch
) y obtiene una excepción no controlada dentro de ese hilo. En este caso, el hilo saldrá y sufinally
bloque no se ejecutará (la aplicación puede continuar ejecutándose en este caso)Este escenario es bastante raro, pero es solo para mostrar que la respuesta NO SIEMPRE es "Sí", es la mayoría de las veces "Sí" y, a veces, en raras ocasiones, "No".
fuente
El objetivo principal de finalmente bloquear es ejecutar lo que esté escrito dentro de él. No debe depender de lo que suceda en try o catch. Sin embargo, con System.Environment.Exit (1) la aplicación saldrá sin pasar a la siguiente línea de código.
fuente