.net - español - Por qué usar Finally in Try... Catch
try catch javascript ejemplo (14)
Veo que Finally
en Try .. Catch
siempre se ejecutará después de cualquier parte de la ejecución del bloque try catch.
¿Es diferente simplemente omitir la sección Finally
y simplemente ejecutarla después, fuera del bloque try catch?
Ejemplo 1, Prueba ... Captura ... Finalmente ... Fin Prueba
Try
''Do something
Catch ex As Exception
''Handle exception
Finally
''Do cleanup
End Try
Ejemplo 2, Prueba ... Atrapa ... Termina Prueba ... Haz las cosas finalmente afuera
Try
''Do something
Catch ex As Exception
''Handle exception
End Try
''Do cleanup
Además de lo que dijeron los demás, semánticamente creo que son diferentes.
El código en el bloque finally indica claramente que está realizando tareas de tipo de finalización para el contenido contenido en try-catch. Creo que esto lo hace más claro para leer.
Código con cuatro botones de radio:
- Regreso en TRY
- Regreso en CATCH
- Lanzar en CATCH
Terminar CATCH
private void checkFinally() { try { doFinally(); } catch { Console.WriteLine(" Breaking news: a crash occured. "); } } private void doFinally() { Console.WriteLine(" "); Console.Write("Here goes: " + (radioReturnInTry.Checked ? "2. Return in try: " : (radioReturnInCatch.Checked? "3. Retrun in catch: " : (radioThrowInCatch.Checked? "4. Throw in catch: " : "1. Continue in catch: "))) ); try { if (radioReturnInTry.Checked) { Console.Write(" Returning in try. "); return; } Console.Write(" Throwing up in try. "); throw new Exception("check your checkbox."); } catch (Exception ex) { Console.Write(" ...caughtcha! "); if (radioReturnInCatch.Checked) { Console.Write("Returning in catch. "); return; } if (radioThrowInCatch.Checked) { Console.Write(" Throwing up in catch. "); throw new Exception("after caught"); } } finally { Console.Write(" Finally!!"); } Console.WriteLine(" Done!!!"); // before adding checkboxThrowInCatch, // this would never happen (and was marked grey by ReSharper) }
Salida:
- Aquí va: 1. Continuar en la captura: Lanzar en el intento. ... atrapado! ¡¡Finalmente!! ¡¡¡Hecho!!!
- Aquí va: 2. Regresar en el intento: Regresar en el intento. ¡¡Finalmente!!
- Aquí va: 3. Recuperar en la captura: tirar al intentar. ... atrapado! Volviendo en captura. ¡¡Finalmente!!
- Aquí va: 4. Lanzar la captura: Lanzar en el intento. ... atrapado! Lanzando en captura. ¡¡Finalmente!! Últimas noticias: se produjo un bloqueo.
Para resumir: finalmente se ocupa de dos cosas:
- Del código que regresó en el intento o en la captura.
- O si tuvo una excepción en el intento, Y LANZÓ una excepción en la captura,
- o, si tuvo una excepción en el intento, Y NO TOMÓ esa excepción,
Finalmente para resumir "FINALMENTE" : Finalmente no hace nada especial si lo intentas, y
- NO VOLVIÓ,
- y atrapó cualquier excepción durante el juicio, y luego
- NO REGRESO en la captura tampoco, y
- NO HIZO LANZAR o tiene un código que vomita.
Y por último pero no menos importante (finalmente): si tiene una excepción en su código que USTED NO CAPTÓ, su código volará, SIN ALCANZAR EL FINALMENTE.
Espero que esto esté claro. (Ahora es para mí ...)
Moshe
Catch no se ejecutará después de ninguna parte de la ejecución del bloque try catch. Catch solo se ejecutará si se lanza una excepción y el bloque catch puede manejar ese tipo de excepción.
El bloque finally es el que se ejecutará cuando se complete el bloque try. Por completo, quiero decir que termina normalmente, o sale de alguna forma (se sale de un bucle, regresa del método, arroja una excepción, etc.)
Si coloca el código fuera del bloque finally y se lanza una excepción (por ejemplo), entonces el código no se puede ejecutar si la excepción no se captura, o se vuelve a lanzar en el bloque catch, o si se lanza una nueva excepción en el catch bloquear. Si lo coloca dentro del bloque finally, entonces se ejecutará.
Básicamente, la limpieza debe colocarse en el bloque finally.
Después de leer la respuesta a mi comentario anterior, comencé a pensar en algunas cosas.
La pregunta básicamente no puede responderse completamente sin conocer el código en cuestión.
La razón es que no todos los códigos se pueden poner en un bloque finally. Por ejemplo, las declaraciones de rendimiento no se permiten en bloques finales (y de captura). El bloque try puede tener varias ejecuciones de ejecución donde algunas devoluciones y otras no. El finalmente se ejecuta en todos los casos, mientras que en el ejemplo sin finalmente, ese no sería el caso para el código de limpieza. Además, no puedes saltar (ir) a un bloque final, aunque es muy raro que puedas saltar al código después del bloque catch. Tampoco puedes regresar de un bloqueo final.
Hay bastantes casos, aunque muy poco comunes, en los que la respuesta depende del código real.
El bloque Finally se ejecutará independientemente de si la función se cierra debido a una excepción. (hay algunas excepciones a esta regla, consulte esta pregunta de para obtener más información).
Por ejemplo:
Try
''Do something
Catch ex As Exception
if ''Some Condition
throw ex
else
''Handle exception
Finally
''Do cleanup
End Try
En este caso, el bloque Finally se ejecutará aún aunque pueda lanzar una excepción fuera de la función.
Esta es una buena práctica para entrar porque garantiza que su código de limpieza siempre se ejecute. Por supuesto, el uso de la expresión "Resoource Acquisition Is Initialization " es una manera mucho más limpia de garantizar que los recursos se limpien, pero no estoy lo suficientemente familiarizado con VB.net para saber si esto es posible.
Esta es una buena idea cuando se trata de conexiones de bases de datos o en cualquier momento que los objetos deban ser eliminados. En caso de que algo salga mal mientras se ejecutan consultas, aún puede cerrar la conexión de forma segura. También ayuda a limpiar el código que el bloque fuera del bloque try / catch / finally no puede acceder.
Finalmente contiene un código que necesita ser evaluado en todas las condiciones [si se produjo o no una excepción].
No hay forma de salir de un bloque try sin ejecutar su bloque finally. Si el bloque finally existe, siempre se ejecuta. (Esta afirmación es verdadera para todos los intentos y propósitos. Hay una manera de salir de un bloque try sin ejecutar el bloque finally. Si el código ejecuta un System.exit (0); desde dentro de un bloque try, la aplicación termina sin el finally Por otro lado, si desenchufa la máquina durante un bloqueo de prueba, finalmente no se ejecutará.
El uso principal es para deshacerse de objetos. Será útil cuando desee cerrar recursos definidos por el usuario, como archivos, recursos abiertos (db stmts).
Editar
Finalmente, no se ejecutará después de una excepción de .
Hacer la limpieza en un bloque final es garantizar que se ejecute. Si el bloque catch no se ocupa de la excepción (es decir, simplemente lo registra), o incluso causa otra excepción, el código en el bloque finally seguirá ejecutándose.
La diferencia es cuando el código en el bloque try
arroja una excepción que no atrapa el bloque catch
.
Normalmente, un bloque catch captaría un tipo específico de excepción y dejaría pasar todo lo demás. En ese caso, el bloque finally
seguirá ejecutándose.
El bloque finally
también se ejecutará si el código en el bloque try
return
s.
Lo que uso a menudo es (lo resumí en un aspecto, pero esto es de lo que saqué el aspecto de):
public static DoLengthyProcessing(this Control control, Action<Control> action)
{
Cursor oldCursor = control.Cursor
try
{
control.Cursor = Cursors.WaitCursor;
action(control);
}
catch (Exception ex)
{
ErrorHandler.Current.Handler(ex);
}
finally
{
control.Cursor = oldCursor;
}
}
O bien, use AOP (como yo).
Por lo que puedo recordar, nunca he usado un bloque try / catch / finally en mi código .NET.
En general, rara vez se necesitan excepciones en el nivel medio. Las excepciones generalmente se propagan a un manejador de nivel superior en el nivel de presentación (y posiblemente se capturan y redisuelven en un límite de nivel para que puedan registrarse).
Por lo tanto, en el nivel intermedio, con mayor frecuencia verá try / finally (o la declaración "using") para que los recursos se limpien. Y en try / catch en el controlador de nivel superior en el nivel de presentación.
En los raros casos en que necesito detectar una excepción y hacer una limpieza, preferiría refactorizarme para que lo siguiente:
try
{
... do something
}
catch
{
... handle exception
}
finally
{
... cleanup
}
se convierte en:
try
{
DoSomethingAndCleanup();
}
catch
{
... handle exception
}
...
private void DoSomethingAndCleanup()
{
try
{
... do something
}
finally
{
... cleanup
}
}
En mi humilde opinión esto es mucho más limpio.
Sí, es diferente. Finalmente siempre se ejecutará (salvo bloqueo de programa). Si la función sale dentro del bloque try catch, o si se produce otro error en try o catch, finalmente se ejecutará. No obtendrá esa funcionalidad sin utilizar la instrucción finally.
Usas finalmente para el código de limpieza, por ejemplo, conexiones db o archivos abiertos que deben estar cerca. Prácticamente cualquier código de limpieza que deba ejecutarse sin considerar una excepción o no
también, su manejo de excepciones podría requerir volver a lanzar la excepción u otra excepción, en cuyo caso el código después del bloque no se ejecutará
Finalmente debería usarse para todo lo que se necesita hacer para mantener un sistema consistente. Esto generalmente significa liberar recursos
Finalmente, siempre se ejecuta, sin importar la excepción que se haya lanzado. Se debe usar para liberar recursos, en los siguientes casos:
- Finaliza una conexión
- Cierre un manejador de archivos
- Memoria libre
- Cerrar una conexión de base de datos
Déjame dar un ejemplo completo. Imagine que está enviando mensajes a través de la red. En pseudo-código:
// With finally | //Without finally
try{ | try{
send_message() | send_message()
} catch(NetworkError){ | } catch(NetworkError){
deal_with_exception() | deal_with_exception()
} finally { | }
finalizes_connection() | finalizes_connection()
} |
La única diferencia de ambos códigos es cuando lo que se mantiene en el bloque try
genera una excepción que no es NetworkError
, por ejemplo, MethodNotFound
. En el primer caso, se llamará al método finalizes_connection()
, y en el segundo, no.
Una conexión se realiza naturalmente a través de más de un programa. Entonces, ¿qué sucede en el caso de una excepción MethodNotFound
para el otro programa? En el primer caso, su programa terminará la conexión y el otro programa y estará feliz. En el segundo caso, el otro programa puede esperar su respuesta para siempre. ¿Qué ocurre si el otro programa solo puede recibir una conexión por tiempo? Acabas de molestar el otro programa también.
Esto también se aplicaría a un archivo, por ejemplo, que abrió y otros programas no podrían abrirse para su lectura (en Windows). Y para la memoria, nunca se libera y ahora tiene una pérdida de memoria.