¿Por qué usar finalmente en C #?

189

Lo que está adentro finalmente los bloques se ejecutan (casi) siempre, entonces, ¿cuál es la diferencia entre encerrar el código en él o dejarlo sin cerrar?

Rodrigo
fuente
3
¿Qué quieres decir con dejarlo sin cerrar?
Ramesh
55
¿Y qué quieres decir con "(casi)"?
Beska
49
Si desconecta el cable de alimentación mientras una máquina está ejecutando una cláusula de prueba, no se invocará la cláusula final.
Dour High Arch
55
jajaja, sí, es cierto, pero realmente no puedes codificar para eso, ¿verdad?
Ed S.
2
@Ed: Usar transacciones. Su cláusula try tiene que hacer algún tipo de cambio temporal o en memoria que pueda persistir en un único cambio atómico en la cláusula final. Esto rara vez es fácil y puede requerir hardware especial.
Dour High Arch

Respuestas:

405

El código dentro de un bloque finalmente se ejecutará independientemente de si hay una excepción o no. Esto es muy útil cuando se trata de ciertas funciones de limpieza que debe ejecutar siempre como cerrar las conexiones.

Ahora, estoy adivinando su pregunta es por qué usted debe 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 declaración catch 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 instrucción catch emite una devolución o arroja una nueva excepción.

Kevin Pang
fuente
3
Hmm Muy similar a lo que dije, pero más claro y más exacto. Definido +1.
Beska
46
esto también se aplica a "return" dentro del bloque try {}.
Lucas
44
de hecho, se aplica incluso sin un bloque catch {} (solo intente / finalmente, dejando que las excepciones aumenten)
Lucas
mejor que el mío, estaba en el trabajo y no quería pasar diez minutos respondiéndolo en detalle. +1
Matt Briggs
2
Sí, esto era exactamente lo que tenía en mente: D Ahora lo entiendo.
Rodrigo
62

La mayoría de las ventajas de usar try-finally ya se han señalado, pero pensé en agregar 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, particularmente cuando necesita realizar una limpieza (desechar recursos), aunque un bloque de uso suele ser mejor en este caso.

Noldorin
fuente
2
Esta es, literalmente, la única razón por la que uso finalmente
Christopher Townsend, el
12

cada vez que use solicitudes de código no administradas como lectores de flujo, solicitudes de db, etc. y desea detectar la excepción, luego use try catch finalmente y cierre la secuencia, el lector de datos, etc., finalmente, si no lo hace cuando se produce un error, 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 desea 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

Bob el conserje
fuente
2
Dispose () también cerrará () la conexión, no es necesario llamar a ambos. Cerrar () NO Dipose (), puede volver a abrir la conexión.
Lucas
Bien, gracias por mencionar el uso. Tendría que responder, de lo contrario.
Dan Rosenstark el
11

Porque finalmente se ejecutará incluso si no manejas una excepción en un bloque catch.

Matt Briggs
fuente
7

Finalmente, las declaraciones pueden ejecutarse 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
}
Prateek Gupta
fuente
7

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..catchbloqueo, independientemente de si su bloque try produjo o no una excepción.

Eso lo hace perfecto para cosas como liberar recursos, conexiones db, identificadores de archivos, etc.

David Alpert
fuente
3
Todos esos ejemplos generalmente se sirven mejor con un bloque de uso, pero eso realmente no resta valor a su respuesta.
Joel Coehoorn
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 generará una excepción y se manejará, pero la declaración llamada StreamReader.Close();nunca se ejecutará.
Debido a esto, los recursos asociados con el lector nunca se lanzaron.

  • 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 utiliza 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 otra manera.

Nadar Ariven
fuente
2

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 la aplicación no se bloquea por completo, podría quedar con un cursor confuso.

Chris Doggett
fuente
2

A veces no desea manejar una excepción (sin bloqueo), pero desea ejecutar un código de limpieza.

Por ejemplo:

try
{
    // exception (or not)
}
finally
{
    // clean up always
}
markom
fuente
Si no se detecta la excepción, la ejecución del último bloque depende de si el sistema operativo elige activar una operación de desenrollado de excepción.
Vikas Verma
2

El último bloque es valioso para limpiar los recursos asignados en el bloque de prueba, así como para ejecutar cualquier código que deba ejecutarse incluso si hay una excepción. El control siempre se pasa al bloque finalmente, independientemente de cómo salga el bloque try.

cgreeno
fuente
1

Ahh ... creo que veo lo que estás diciendo! Me tomó un segundo ... te preguntas "por qué colocarlo en el bloque finalmente en lugar de después del bloque finalmente y completamente fuera del try-catch-finally".

Como ejemplo, podría deberse a que está deteniendo la ejecución si arroja un error, pero aún desea limpiar recursos, como archivos abiertos, conexiones de bases de datos, etc.

Beska
fuente
1

El flujo de control del bloque Finalmente es posterior al bloque Try o Catch.

[1. First Code]
[2. Try]
[3. Catch]
[4. Finally]
[5. After Code]

con la 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 retorno 1> 2> 4

Ranald Fong
fuente
0

Como se menciona en la documentación :

Un uso común de catch y finalmente juntos es obtener y usar recursos en un bloque try, lidiar con circunstancias excepcionales en un bloque catch y liberar los recursos en el bloque finalmente.

También vale la pena leer esto , que dice:

Una vez que se encuentra una cláusula catch coincidente, el sistema se prepara para transferir el control a la primera declaración de la cláusula catch. Antes de que comience la ejecución de la cláusula catch, el sistema primero ejecuta, en orden, cualquier cláusula finalmente asociada con las declaraciones try más anidadas que la que detectó la excepción.

Por lo tanto, está claro que el código que reside en una finallycláusula se ejecutará incluso si una catchcláusula anterior tenía una returndeclaración.

Nexaspx
fuente