c# - propiedades - ¿Se activará el código en una instrucción Finally si devuelvo un valor en un bloque Try?
personalizar exception c# (13)
Aquí hay una pequeña prueba:
class Class1
{
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("before");
Console.WriteLine(test());
Console.WriteLine("after");
}
static string test()
{
try
{
return "return";
}
finally
{
Console.WriteLine("finally");
}
}
}
El resultado es:
before
finally
return
after
Estoy revisando un código para un amigo y digo que estaba usando una declaración de retorno dentro de un bloque try-finally. ¿Todavía se dispara el código en la sección Finalmente a pesar de que el resto del bloque try no lo hace?
Ejemplo:
public bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn''t seem to get executed
}
finally
{
//code in question
}
}
Cotización de MSDN
finalmente se utiliza para garantizar que un bloque de instrucciones de código se ejecute independientemente de cómo se salga del bloque try anterior.
El propósito 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 se cerrará sin pasar a la siguiente línea de código.
En el 99% de los escenarios, se garantizará que el código que se encuentra dentro del bloque finally
se ejecutará. Sin embargo, piense en este escenario: tiene un hilo que tiene un try
-> finally
block (sin catch
) y obtiene una excepción no controlada dentro de ese bloque. hilo. En este caso, el hilo se cerrará y su bloque final 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 ES SIEMPRE "Sí", es la mayoría de las veces "Sí" y, a veces, en condiciones excepcionales, "No".
En general sí, el finalmente se ejecutará.
Para los siguientes tres escenarios, finalmente se ejecutará SIEMPRE :
- No se producen excepciones.
- Excepciones síncronas (excepciones que ocurren en el flujo normal del programa).
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 envuelve automáticamente las excepciones que no cumplen con CLS. C # no puede lanzar excepciones de reclamo que no sean de CLS, pero lenguajes como C ++ pueden. C # podría estar llamando a un código escrito en un idioma que puede generar excepciones no compatibles con CLS. - ThreadAbortException asíncrono
A partir de .NET 2.0, una excepción ThreadAbortException ya no impedirá que se ejecute finalmente. Ahora se eleva ThreadAbortException antes o después de la finalización. Finalmente, siempre se ejecutará y no se interrumpirá por un aborto de subproceso, siempre que el intento se haya introducido antes de que se abortara el subproceso.
El siguiente escenario, el finalmente no se ejecutará:
Exception asíncrono.
A partir de .NET 2.0, un desbordamiento de pila hará que el proceso finalice. Finalmente no se ejecutará, a menos que se aplique una restricción adicional para hacer 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 cuando sea crítico que el código de limpieza siempre se ejecute, después de que todo el proceso se esté cerrando en el desbordamiento de la pila de todos modos y, por lo tanto, todos los objetos administrados se limpiarán de forma predeterminada. Por lo tanto, el único lugar donde un CER debe ser relevante es para los recursos que se asignan fuera del proceso, por ejemplo, manejadores no administrados.
Por lo general, el código no administrado está envuelto por alguna clase administrada antes de ser consumido por el código de usuario. La clase contenedora administrada usará un SafeHandle para envolver 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 los CERs llenos del código de usuario.
Por lo tanto, el hecho de que finalmente no se ejecute en Exception no debería afectar al código de usuario, ya que el proceso terminará 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, use un CER de la siguiente manera; pero tenga en cuenta que esta es una mala práctica: el concepto no administrado debe resumirse en una clase (s) administrada (s) y SafeHandle apropiado (s) por diseño.
p.ej,
// No code can appear after this line, before the try
RuntimeHelpers.PrepareConstrainedRegions();
try
{
// This is *NOT* a CER
}
finally
{
// This is a CER; guaranteed to run, if the try was entered,
// even if a Exception occurs.
}
Hay una excepción muy importante a esto que no he visto mencionada 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 bloque catch
(no solo las extrañas Exceptions
y cosas de ese estilo), y no tiene el bloque try/catch/finally
dentro de otro bloque try/catch
, finally
bloquea no ejecutará Esto se puede demostrar fácilmente, y si no lo hubiera visto, dada la frecuencia con la que he leído que solo son casos minúsculos muy raros que pueden causar que un bloque final no se ejecute, no lo hubiera creído.
static void Main(string[] args)
{
Console.WriteLine("Beginning demo of how finally clause doesn''t get executed");
try
{
Console.WriteLine("Inside try but before exception.");
throw new Exception("Exception #1");
}
catch (Exception ex)
{
Console.WriteLine($"Inside catch for the exception ''{ex.Message}'' (before throwing another exception).");
throw;
}
finally
{
Console.WriteLine("This never gets executed, and that seems very, very wrong.");
}
Console.WriteLine("This never gets executed, but I wasn''t expecting it to.");
Console.ReadLine();
}
Estoy seguro de que hay una razón para esto, pero es extraño que no sea más conocido. (Se señala here por ejemplo, pero no en ninguna parte de esta pregunta en particular).
Me doy cuenta de que llego tarde a la fiesta, pero en el escenario (que difiere del ejemplo de 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 finally depende de si el sistema operativo elige o no desencadenar una excepción".
Solo se garantiza que el bloque finally se ejecute si alguna otra función (como Main) más arriba en la pila de llamadas detecta la excepción. Este detalle generalmente no es un problema porque todos los programas de tiempo de ejecución (CLR y OS) C # se ejecutan en la mayoría de los recursos que posee un proceso cuando se cierra (manejadores de archivos, etc.). Sin embargo, en algunos casos puede ser crucial: una operación de base de datos que está a mitad de camino y que desea confirmar. relajarse; o alguna conexión remota que puede no cerrarse automáticamente por el sistema operativo y luego bloquear un servidor.
Normalmente sí. La sección finally está garantizada para ejecutar lo que ocurra, incluidas excepciones o declaraciones de devolución. Una excepción a esta regla es una excepción asíncrona que ocurre en el hilo ( OutOfMemoryException
, Exception
).
Para obtener más información sobre las excepciones asíncronas y el código confiable en esas situaciones, lea acerca de las regiones de ejecución restringida .
Respuesta simple: sí.
Sí, finalmente llame.
public static bool someMethod()
{
try
{
return true;
throw new Exception("test"); // doesn''t seem to get executed
}
finally
{
//code in question
}
}
Sí. Ese es, de hecho, el punto principal de una declaración final. A menos que ocurra algo catestrófico (sin memoria, computadora desenchufada, etc.), la sentencia finally debe ejecutarse siempre.
Tampoco se activará en una excepción no capturada y se ejecutará en un subproceso alojado en un Servicio de Windows
Finalmente no se ejecuta cuando se está ejecutando un subproceso en un servicio de Windows
finalmente no se ejecutará en caso de que esté saliendo de la aplicación usando System.exit (0); como en
try
{
System.out.println("try");
System.exit(0);
}
finally
{
System.out.println("finally");
}
el resultado sería justo: tratar