¿Por qué try {finally} finalmente {good} es bueno; try {catch} catch {} es malo?


He visto a la gente decir que es una mala forma de usar la captura sin argumentos, especialmente si esa captura no hace nada:

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
catch   // No args, so it will catch any exception
{}
reader.Close();

Sin embargo, esto se considera buena forma:

StreamReader reader=new  StreamReader("myfile.txt");
try
{
  int i = 5 / 0;
}
finally   // Will execute despite any exception
{
  reader.Close();
}

Por lo que puedo decir, la única diferencia entre poner código de limpieza en un bloque final y poner código de limpieza después del intento..catch blocks es si tiene instrucciones return en su bloque try (en ese caso, el código de limpieza en finally se ejecutará, pero el código después del try..catch will ni).

De lo contrario, ¿qué tiene de especial finalmente?

Author: FMFF, 2008-09-24

20 answers

La gran diferencia es que try...catch se tragará la excepción, ocultando el hecho de que se produjo un error. try..finally ejecutará su código de limpieza y luego la excepción continuará, para ser manejada por algo que sepa qué hacer con ella.

 331
Author: Khoth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:12:51

"Finalmente" es una declaración de "Algo que siempre debe hacer para asegurarse de que el estado del programa esté sano". Como tal, siempre es una buena forma de tener uno, si hay alguna posibilidad de que las excepciones puedan deshacerse del estado del programa. El compilador también hace todo lo posible para asegurarse de que su código Finalmente se ejecute.

"Catch" es una declaración de "Puedo recuperarme de esta excepción". Solo debe recuperarse de las excepciones que realmente puede corregir-catch sin argumentos dice " Hey, puedo recuperarse de nada!", que casi siempre es falso.

Si fuera posible recuperarse de cada excepción, entonces realmente sería una disputa semántica, sobre lo que está declarando su intención de ser. Sin embargo, no lo es, y es casi seguro que los marcos por encima de la suya estarán mejor equipados para manejar ciertas excepciones. Como tal, use finalmente, obtenga su código de limpieza ejecutado de forma gratuita, pero aún así deje que los manejadores más conocedores se ocupen del problema.

 56
Author: Adam Wright,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:43:33

Porque cuando una sola línea lanza una excepción, no lo sabrías.

Con el primer bloque de código, la excepción simplemente será absorbida, el programa continuará ejecutándose incluso cuando el estado del programa pueda ser incorrecto.

Con el segundo bloque, la excepción será lanzado y burbujas hacia arriba pero el reader.Close() todavía está garantizado para funcionar.

Si no se espera una excepción, entonces no intentes..atrapa el bloque para que, será difícil depurar más tarde cuando el programa entró en un mal estado y no tiene una idea de por qué.

 32
Author: chakrit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:14:23

Finalmente se ejecuta sin importar qué. Por lo tanto, si su bloque try tuvo éxito se ejecutará, si su bloque try falla, ejecutará el bloque catch y luego el bloque finally.

Además, es mejor tratar de usar la siguiente construcción:

using (StreamReader reader=new  StreamReader("myfile.txt"))
{
}

Como la instrucción using se envuelve automáticamente en un try / finally y la secuencia se cerrará automáticamente. (Usted tendrá que poner un try / catch alrededor de la instrucción using si usted quiere realmente coger el salvedad).

 20
Author: Mark Ingram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-20 13:40:40

Mientras que los siguientes 2 bloques de código son equivalentes, no son iguales.

try
{
  int i = 1/0; 
}
catch
{
  reader.Close();
  throw;
}

try
{
  int i = 1/0;
}
finally
{
  reader.Close();
}
  1. 'finalmente' es un código que revela la intención. Usted declara al compilador y a otros programadores que este código necesita ejecutarse pase lo que pase.
  2. si tiene varios bloques de captura y tiene código de limpieza, finalmente necesita. Sin finalmente, estaría duplicando su código de limpieza en cada bloque catch. (Principio SECO)

Finalmente los bloques son especiales. El CLR reconoce y trata código con un bloque finally separado de los bloques catch, y el CLR va a grandes longitudes para garantizar que un bloque finally siempre se ejecutará. No es solo azúcar sintáctica del compilador.

 6
Author: Robert Paulson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 20:55:21

Estoy de acuerdo con lo que parece ser el consenso aquí: un 'catch' vacío es malo porque enmascara cualquier excepción que pudiera haber ocurrido en el bloque try.

También, desde un punto de vista de legibilidad, cuando veo un bloque 'try' asumo que habrá una declaración 'catch' correspondiente. Si solo está utilizando un ' try 'para asegurarse de que los recursos están desasignados en el bloque' finally', podría considerar la instrucción ' using ' en su lugar:

using (StreamReader reader = new StreamReader('myfile.txt'))
{
    // do stuff here
} // reader.dispose() is called automatically

Puede usar la instrucción 'using' con cualquier objeto que implementa IDisposable. El método dispose() del objeto se llama automáticamente al final del bloque.

 5
Author: Chris Lawlor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:28:06

El intento..finalmente, el bloque seguirá lanzando cualquier excepción que se eleve. Todo lo que finally hace es asegurarse de que el código de limpieza se ejecute antes de que se lance la excepción.

El intento..la captura con una captura vacía consumirá por completo cualquier excepción y ocultará el hecho de que sucedió. El lector estará cerrado, pero no se sabe si sucedió lo correcto. ¿Y si tu intención fuera escribir i en el archivo? En este caso, no llegará a esa parte del código y miarchivo.txt estará vacío. ¿Todos los métodos aguas abajo manejan esto correctamente? Cuando vea el archivo vacío, ¿podrá adivinar correctamente que está vacío porque se lanzó una excepción? Mejor lanzar la excepción y dejar que se sepa que estás haciendo algo mal.

Otra razón es el intento..la captura hecha así es completamente incorrecta. Lo que estás diciendo al hacer esto es, "No importa lo que pase, puedo manejarlo."¿Qué pasa con StackOverflowException, puede limpiar después de eso? ¿Qué pasa con OutOfMemoryException? En general, solo debe manejar las excepciones que espera y sabe cómo manejar.

 3
Author: OwenP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:16:01

Si no sabe qué tipo de excepción capturar o qué hacer con él, no tiene sentido tener una declaración catch. Solo debe dejarlo para que una persona de más alto nivel que pueda tener más información sobre la situación sepa qué hacer.

Todavía debe tener una sentencia finally allí en caso de que haya una excepción, para que pueda limpiar los recursos antes de que se lance esa excepción al llamador.

 2
Author: Mark Cidade,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:13:20

Desde una perspectiva de legibilidad, está diciendo más explícitamente a los futuros lectores de código: "esto de aquí es importante, debe hacerse sin importar lo que pase."Esto es bueno.

Además, las declaraciones de captura vacías tienden a tener un cierto "olor". Pueden ser una señal de que los desarrolladores no están pensando en las diversas excepciones que pueden ocurrir y cómo manejarlas.

 2
Author: Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:14:15

Finalmente es opcional no no hay razón para tener un bloque "Finalmente" si no hay recursos para limpiar.

 2
Author: Guy Starbuck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:14:39

Tomado de: aquí

Las excepciones de cría y captura no deben ocurrir rutinariamente como parte de la ejecución exitosa de un método. Al desarrollar bibliotecas de clases, al código cliente se le debe dar la oportunidad de probar una condición de error antes de emprender una operación que pueda resultar en que se genere una excepción. Por ejemplo, System. IO. FileStream proporciona una propiedad CanRead que se puede comprobar antes de llamar al método Read, evitando que una posible excepción sea planteado, como se ilustra en el siguiente fragmento de código:

Dim str As Stream = GetStream() If (str.Puede leer) Entonces 'código para leer la secuencia Fin If

La decisión de verificar el estado de un objeto antes de invocar un método particular que puede generar una excepción depende del estado esperado del objeto. Si se crea un objeto FileStream utilizando una ruta de archivo que debería existir y un constructor que debería devolver un archivo en modo de lectura, comprobar la propiedad CanRead no es necesario; la incapacidad de leer el FileStream sería una violación del comportamiento esperado de las llamadas al método realizadas, y se debería plantear una excepción. Por el contrario, si se documenta un método que devuelve una referencia de flujo de archivos que puede o no ser legible, se recomienda verificar la propiedad CanRead antes de intentar leer los datos.

Para ilustrar el impacto en el rendimiento que puede causar el uso de una técnica de codificación "run until exception", el rendimiento de un cast, que arroja un InvalidCastException si el cast falla, se compara con el operador C# as, que devuelve nulls si un cast falla. El rendimiento de las dos técnicas es idéntico para el caso en que el molde es válido (ver Prueba 8.05), pero para el caso en que el molde no es válido, y el uso de un molde causa una excepción, el uso de un molde es 600 veces más lento que el uso del operador as (ver Prueba 8.06). El impacto de alto rendimiento de la técnica de lanzamiento de excepción incluye el costo de asignación, lanzamiento y captura la excepción y el costo de la posterior recolección de basura del objeto de excepción, lo que significa que el impacto instantáneo de lanzar una excepción no es tan alto. A medida que se lanzan más excepciones, la recolección frecuente de basura se convierte en un problema, por lo que el impacto general del uso frecuente de una técnica de codificación de lanzamiento de excepciones será similar a la prueba 8.05.

 2
Author: SpoiledTechie.com,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:14:42

Es una mala práctica añadir una cláusula catch solo para repensar la excepción.

 2
Author: Bastien Vandamme,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-27 12:48:15

Use Try..Catch..Finally, si su método sabe cómo manejar la excepción localmente. La Excepción ocurre en Try, Manejado en Catch y después de que la limpieza se hace en Finally.

En caso de que su método no sepa cómo manejar la excepción, pero necesita una limpieza una vez que se ha producido, use Try..Finally

De esta manera, la excepción se propaga a los métodos de llamada y se maneja si hay instrucciones de captura adecuadas en los métodos de llamada.Si no hay controladores de excepción en el método actual o cualquiera de los métodos de llamada, entonces la aplicación se bloquea.

Mediante Try..Finally se asegura que la limpieza local se realiza antes de propagar la excepción a los métodos invocadores.

 2
Author: manjuv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-20 05:56:32

Con finalmente, puede limpiar recursos, incluso si su declaración catch lanza la excepción al programa que llama. Con su ejemplo que contiene la instrucción catch vacía, hay poca diferencia. Sin embargo, si en su captura, hace un poco de procesamiento y lanza el error, o incluso simplemente no tiene una captura en absoluto, finalmente todavía se ejecutará.

 1
Author: Kibbee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:14:18

Bueno, para empezar, es una mala práctica atrapar excepciones que no te molestes en manejar. Consulte El capítulo 5 sobre el rendimiento de.NET en Mejorando el Rendimiento y la Escalabilidad de las Aplicaciones de. NET. Nota al margen, probablemente deberías estar cargando la secuencia dentro del bloque try, de esa manera, puedes atrapar la excepción pertinente si falla. Crear la secuencia fuera del bloque try frustra su propósito.

 1
Author: Factor Mystic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:18:17

Si lees C# para programadores entenderás, que el bloque finalmente fue diseñado para optimizar una aplicación y evitar fugas de memoria.

El CLR no elimina completamente las fugas... las fugas de memoria pueden ocurrir si el programa mantiene inadvertidamente referencias a objetos no deseados

Por ejemplo, cuando abre una conexión de archivo o base de datos, su máquina asignará memoria para atender esa transacción, y esa memoria no se conservará a menos que la o comando cercano fue ejecutado. pero si durante la transacción, se produjo un error, el comando de procedimiento no se terminará a menos que estuviera dentro del bloque try.. finally...

catch fue diferente de finally en el sentido de que, catch fue diseñado para darle la manera de manejar/administrar o interpretar el error en sí mismo. Piensa en ello como una persona que te dice " oye, atrapé a algunos chicos malos, ¿qué quieres que les haga?" mientras que finally fue diseñado para asegurarse de que sus recursos se colocaron correctamente. Piensa en es de alguien que si hay o no algunos chicos malos se asegurará de que su propiedad todavía estaba a salvo.

Y debes permitir que esos dos trabajen juntos para siempre.

Por ejemplo:

try
{
  StreamReader reader=new  StreamReader("myfile.txt");
  //do other stuff
}
catch(Exception ex){
 // Create log, or show notification
 generic.Createlog("Error", ex.message);
}
finally   // Will execute despite any exception
{
  reader.Close();
}
 1
Author: dr.Crow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-29 10:33:10

Entre muchas razones, las excepciones son muy lentas de ejecutar. Usted puede fácilmente paralizar sus tiempos de ejecución si esto sucede mucho.

 0
Author: lotsoffreetime,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:14:41

El problema con los bloques try/catch que capturan todas las excepciones es que su programa ahora está en un estado indeterminado si ocurre una excepción desconocida. Esto va completamente en contra de la regla fail fast: no desea que su programa continúe si se produce una excepción. El anterior try / catch incluso atraparía fuera Dememoryexceptions, pero ese es definitivamente un estado en el que su programa no se ejecutará.

Los bloques Try/finally le permiten ejecutar código de limpieza mientras sigue fallando rápidamente. Para la mayoría circunstancias, solo desea capturar todas las excepciones a nivel global, para que pueda registrarlas y luego salir.

 0
Author: David Mohundro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:14:48

La diferencia efectiva entre sus ejemplos es insignificante siempre y cuando no se produzcan excepciones.

Si, sin embargo, se lanza una excepción mientras se está en la cláusula 'try', el primer ejemplo la tragará completamente. El segundo ejemplo elevará la excepción al siguiente paso de la pila de llamadas, por lo que la diferencia en los ejemplos indicados es que uno oculta completamente cualquier excepción (primer ejemplo), y el otro (segundo ejemplo) retiene la información de la excepción para un potencial posterior manejando mientras se sigue ejecutando el contenido en la cláusula' finally'.

Si, por ejemplo, pusieras código en la cláusula 'catch' del primer ejemplo que lanzó una excepción (ya sea la que se planteó inicialmente, o una nueva), el código de limpieza del lector nunca se ejecutaría. Finalmente ejecuta independientemente de de lo que sucede en la cláusula 'catch'.

Por lo tanto, la principal diferencia entre 'catch' y 'finally' es que el contenido del bloque 'finally' (con algunos raros excepciones) puede considerarse garantizado para ejecutarse, incluso frente a una excepción inesperada, mientras que cualquier código que siga una cláusula 'catch' (pero fuera de una cláusula 'finally') no tendría dicha garantía.

Incidentalmente, Stream y StreamReader implementan identificable, y pueden ser envueltos en un bloque 'using'. Los bloques' Using ' son el equivalente semántico de try / finally (no 'catch'), por lo que su ejemplo podría expresarse de manera más concisa como:

using (StreamReader reader = new  StreamReader("myfile.txt"))
{
  int i = 5 / 0;
}

...que cerrará y deseche la instancia de StreamReader cuando salga de su ámbito. Espero que esto ayude.

 0
Author: Jared,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 18:28:06

Try {catch} catch {} no siempre es malo. No es un patrón común, pero tiendo a usarlo cuando necesito apagar recursos sin importar qué, como cerrar un (posiblemente) sockets abiertos al final de un hilo.

 0
Author: Martin Liesén,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 22:26:20