remarks - ¿Por qué usar finalmente en C#?
remarks c# (14)
Lo que sea que esté dentro finalmente, los bloques se ejecutan (casi) siempre, entonces, ¿cuál es la diferencia entre encerrar el código o dejarlo sin cerrar?
A veces no quiere manejar una excepción (no atrapar bloque), pero quiere que se ejecute algún código de limpieza.
Por ejemplo:
try
{
// exception (or not)
}
finally
{
// clean up always
}
Ahh ... ¡Creo que veo lo que dices! Me tomó un segundo ... te preguntas "por qué colocarlo en el bloque finally en lugar de después del bloque finally y completamente fuera del try-catch-finally".
Como ejemplo, puede deberse a que está suspendiendo la ejecución si arroja un error, pero aún desea limpiar los recursos, como archivos abiertos, conexiones de bases de datos, etc.
Al usar un bloque finally
, puede limpiar cualquier recurso que esté asignado en un bloque try
, y puede ejecutar código incluso si ocurre una excepción en el bloque try
. Normalmente, las instrucciones de un bloque finally
se ejecutan cuando el control deja una instrucción try. La transferencia de control puede ocurrir como resultado de la ejecución normal, de la ejecución de una break, continue, goto, or return
, o de la propagación de una excepción fuera de la instrucción try
.
Dentro de una excepción manejada, se garantiza que se ejecutará el bloque finally
asociado. Sin embargo, si la excepción no se controla, la ejecución del bloque finally
depende de cómo se desencadene la operación de desenrollado de excepción. Eso, a su vez, depende de cómo esté configurada su computadora. Para obtener más información, consulte Procesamiento de excepciones no gestionadas en el CLR .
Normalmente, cuando una excepción no controlada finaliza una aplicación, no es importante si el bloque finally
se ejecuta o no. Sin embargo, si tiene instrucciones en un bloque finally
que se deben ejecutar incluso en esa situación, una solución es agregar un bloque catch
a la instrucción try-finally
. Alternativamente, puede capturar la excepción que podría arrojarse en el bloque try
de una sentencia try-finally
superior de la pila de llamadas. Es decir, puede capturar la excepción en el método que llama al método que contiene la instrucción try-finally
, o en el método que llama a ese método, o en cualquier método en la pila de llamadas. Si no se captura la excepción, la ejecución del bloque finally
depende de si el sistema operativo elige disparar una operación de desenrollado de excepción.
public class ThrowTestA
{
static void Main()
{
int i = 123;
string s = "Some string";
object obj = s;
try
{
// Invalid conversion; obj contains a string, not a numeric type.
i = (int)obj;
// The following statement is not run.
Console.WriteLine("WriteLine at the end of the try block.");
}
finally
{
// To run the program in Visual Studio, type CTRL+F5. Then
// click Cancel in the error dialog.
Console.WriteLine("/nExecution of the finally block after an unhandled/n" +
"error depends on how the exception unwind operation is triggered.");
Console.WriteLine("i = {0}", i);
}
}
// Output:
// Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
//
// Execution of the finally block after an unhandled
// error depends on how the exception unwind operation is triggered.
// i = 123
}
En el siguiente ejemplo, una excepción del método TryCast queda atrapada en un método más arriba en la pila de llamadas. DO#
public class ThrowTestB
{
static void Main()
{
try
{
// TryCast produces an unhandled exception.
TryCast();
}
catch (Exception ex)
{
// Catch the exception that is unhandled in TryCast.
Console.WriteLine
("Catching the {0} exception triggers the finally block.",
ex.GetType());
// Restore the original unhandled exception. You might not
// know what exception to expect, or how to handle it, so pass
// it on.
throw;
}
}
public static void TryCast()
{
int i = 123;
string s = "Some string";
object obj = s;
try
{
// Invalid conversion; obj contains a string, not a numeric type.
i = (int)obj;
// The following statement is not run.
Console.WriteLine("WriteLine at the end of the try block.");
}
finally
{
// Report that the finally block is run, and show that the value of
// i has not been changed.
Console.WriteLine("/nIn the finally block in TryCast, i = {0}./n", i);
}
}
// Output:
// In the finally block in TryCast, i = 123.
// Catching the System.InvalidCastException exception triggers the finally block.
// Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
}
El código dentro de un bloque finally se ejecutará independientemente de si hay una excepción o no. Esto es muy útil cuando se trata de ciertas funciones de limpieza que siempre debe ejecutar como cerrar las conexiones.
Ahora, supongo que tu pregunta es por qué deberías hacer esto:
try
{
doSomething();
}
catch
{
catchSomething();
}
finally
{
alwaysDoThis();
}
Cuando puedes hacer esto:
try
{
doSomething();
}
catch
{
catchSomething();
}
alwaysDoThis();
La respuesta es que muchas veces el código dentro de su instrucción de captura volverá a lanzar una excepción o saldrá de la función actual. Con el último código, el "alwaysDoThis ();" la llamada no se ejecutará si el código dentro de la declaración catch emite una devolución o arroja una nueva excepción.
El flujo de control del bloque Finally es después del bloque Try o Catch.
[1. First Code]
[2. Try]
[3. Catch]
[4. Finally]
[5. After Code]
con Excepción 1> 2> 3> 4> 5 si 3 tiene una declaración de Devolución 1> 2> 3> 4
sin Excepción 1> 2> 4> 5 si 2 tiene una declaración de devolución 1> 2> 4
Explicaré el uso de finalmente con una excepción de lector de archivos Ejemplo
- sin usar finalmente
try{ StreamReader strReader = new StreamReader(@"C:/Ariven/Project/Data.txt"); Console.WriteLine(strReader.ReadeToEnd()); StreamReader.Close(); } catch (Exception ex) { Console.WriteLine(ex.Message); }
en el ejemplo anterior, si falta el archivo llamado Data.txt, se lanzará una excepción y se manejará, pero la instrucción se llama StreamReader.Close();
nunca será ejecutado.
Debido a esto, los recursos asociados con el lector nunca se publicaron.
- Para resolver el problema anterior, usamos finalmente
StreamReader strReader = null; try{ strReader = new StreamReader(@"C:/Ariven/Project/Data.txt"); Console.WriteLine(strReader.ReadeToEnd()); } catch (Exception ex){ Console.WriteLine(ex.Message); } finally{ if (strReader != null){ StreamReader.Close(); } }
Happy Coding :)
Nota: "@" se usa para crear una cadena literal , para evitar el error de "Secuencia de escape no reconocida". El símbolo @ significa leer esa cadena literalmente, y no interpretar los caracteres de control de lo contrario.
Finalmente, las sentencias se pueden ejecutar incluso después del retorno.
private int myfun()
{
int a = 100; //any number
int b = 0;
try
{
a = (5 / b);
return a;
}
catch (Exception ex)
{
Response.Write(ex.Message);
return a;
}
// Response.Write("Statement after return before finally"); -->this will give error "Syntax error, ''try'' expected"
finally
{
Response.Write("Statement after return in finally"); // --> This will execute , even after having return code above
}
Response.Write("Statement after return after finally"); // -->Unreachable code
}
Porque finalmente se ejecutará incluso si no maneja una excepción en un bloque catch.
Supongamos que necesita volver a colocar el cursor en el puntero predeterminado en lugar de un cursor en espera (reloj de arena). Si se lanza una excepción antes de configurar el cursor, y no bloquea completamente la aplicación, podría quedar un cursor confuso.
Ya se han señalado la mayoría de las ventajas de usar try-finally, pero pensé que agregaría esta:
try
{
// Code here that might throw an exception...
if (arbitraryCondition)
{
return true;
}
// Code here that might throw an exception...
}
finally
{
// Code here gets executed regardless of whether "return true;" was called within the try block (i.e. regardless of the value of arbitraryCondition).
}
Este comportamiento lo hace muy útil en diversas situaciones, especialmente cuando necesita realizar una limpieza (disponer de recursos), aunque un bloqueo de uso suele ser mejor en este caso.
cada vez que use solicitudes de código no administradas como lectores de flujo, solicitudes de DNS, etc. y desea capturar la excepción, luego use try catch finalmente y cierre la secuencia, el lector de datos, etc. en el final; si no lo hace, cuando los errores la conexión no se cierra, esto es realmente malo con las solicitudes de db
SqlConnection myConn = new SqlConnection("Connectionstring");
try
{
myConn.Open();
//make na DB Request
}
catch (Exception DBException)
{
//do somehting with exception
}
finally
{
myConn.Close();
myConn.Dispose();
}
si no quiere detectar el error, use
using (SqlConnection myConn = new SqlConnection("Connectionstring"))
{
myConn.Open();
//make na DB Request
myConn.Close();
}
y el objeto de conexión se eliminará automáticamente si hay un error, pero no captura el error
El bloque finally es valioso para limpiar cualquier recurso asignado en el bloque try así como para ejecutar cualquier código que deba ejecutarse incluso si hay una excepción. El control siempre pasa al bloque finally independientemente de cómo salga el bloque try.
finally
, como en:
try {
// do something risky
} catch (Exception ex) {
// handle an exception
} finally {
// do any required cleanup
}
es una oportunidad garantizada para ejecutar código después de su try..catch
bloque de try..catch
, independientemente de si su bloque try lanzó una excepción.
Eso lo hace perfecto para cosas como liberar recursos, conexiones de bases de datos, manejadores de archivos, etc.
Finalmente Block
Si tiene una o más declaraciones que deben ejecutarse antes de salir de la estructura Try
, use un bloque Finally
. Un bloque Finally
es útil para ejecutar cualquier código que deba ejecutarse incluso si hay una excepción. El control se pasa al bloque Finally
independientemente de cómo salga el bloque Try
... Catch
. El control pasa al bloque Finally
justo antes de que salga de la estructura Try
... Catch
. Esto es cierto incluso si ocurre una excepción en cualquier lugar dentro de la estructura Try
. El código en un bloque Finally
se ejecuta incluso si su código encuentra una declaración Return
en un bloque Try
o Catch
.
No es válido transferir explícitamente la ejecución a un bloque Finally
.
La transferencia de la ejecución de un bloque Finally
no es válida, excepto a través de una excepción.