try practices handling exceptions examples example custom code catch best c# exception

practices - throw exception c#



Problemas de bloque Try-Catch-Finally con.NET4.5.1 (3)

Tengo un bloque de código try-catch-finally simple que funciona como se esperaba en .NET3.5, pero el mismo código se comporta completamente diferente en un proyecto creado con .NET4.5.1. Básicamente, en .NET4.5.1, el bloque "finalmente" no se ve afectado si se produce una excepción que no es el comportamiento que esperaba del bloque try-catch-finally. Probé en diferentes máquinas, e hice que otros dos colegas míos también lo intentaran y todos obtuvimos el mismo resultado. Esta es una preocupación para mí, porque uso el bloque finally para cerrar DataReaders, ciertas conexiones y otras cosas.

.NET4.5.1 no golpea el bloque "finalmente" si se lanza una excepción en el modo LIBERAR sin depurador o cuando se ejecuta el archivo EXE compilado LIBERACIÓN . En el modo de depuración, ambas versiones .NET golpean el bloque "finalmente".

Nuevamente, el siguiente código se comporta como se esperaba en el modo .NET3.5 RELEASE sin depurador, pero no en .NET4.5.1. ¿Me estoy perdiendo de algo? ¿Alguien puede ayudar?

class Program { static void Main(string[] args) { try { string a = null; var x = a.Length; Console.WriteLine(x); } catch (Exception ex) { throw; } finally { Console.WriteLine("This is the finally block."); } Console.WriteLine("You should not be here if an exception occured!"); } }


el siguiente código se comporta como se espera en el modo .NET3.5 RELEASE sin depurador pero no en .NET4.5.1. ¿Me estoy perdiendo de algo?

NOTA: había exagerado el nivel de indefinición de este comportamiento; Gracias al comentarista Voo por señalarlo. Debería haber vuelto a la especificación en primer lugar.

Sí. El CLR es requerido por la especificación CLI para finalizar el programa cuando hay una excepción no manejada. Solo se requiere ejecutar bloques finalmente si se maneja la excepción. La especificación es vaga sobre la cuestión de si el CLR es obligatorio, permitido o no permitido para ejecutar finalmente los bloques cuando hay una excepción no controlada; el supuesto seguro es entonces decir que este es un comportamiento que no está definido por la especificación, y que depende de una implementación particular.

El CLR puede elegir ejecutar finalmente los bloques para las excepciones no manejadas, o no, a su antojo. Mucha gente cree que el CLR utiliza este algoritmo: por excepción, recorra la pila de llamadas, ejecutando finalmente los bloques a medida que avanza, en busca de manejadores; Si no se encuentra ningún manejador, finalice el proceso. No se requiere que el CLR se ajuste a este algoritmo en un programa con una excepción no controlada. En particular, se permite al CLR determinar mediante magia negra que no hay un controlador de excepción, y nunca ejecutar ningún bloque final. Ya sea que elija hacerlo o no en algunas versiones del CLR en algunas circunstancias, no lo sé. En ningún caso puede confiar en ese comportamiento para la corrección de su programa porque un programa que tiene una excepción no controlada no es correcto.

La especificación también señala que el CLR puede optar por ofrecer iniciar los depuradores o no, a su antojo. No se requiere que CLR haga lo mismo en la depuración o la versión, y no se requiere que haga lo mismo de una versión a otra.

El problema aquí es que formó una expectativa basada en la experiencia pasada, pero no hay documentación que diga que la experiencia pasada es una base para una predicción del futuro. Más bien, todo lo contrario; Al CLR se le permite cambiar su comportamiento en función de la fase de la luna, si lo desea, en un programa que tiene una excepción no controlada.

Si desea que su programa se comporte de manera predecible , no lance excepciones no manejadas .

Entonces, si te entiendo correctamente, siempre que haya otra captura en algún punto corriente arriba, ¿se ejecutará el bloque finally?

No, no dije eso. Vamos a descomponerlo.

Si hay una excepción no detectada en el programa, entonces el comportamiento del programa está definido por la implementación. Cualquiera que sea el comportamiento que obtenga, ese es el comportamiento que obtuvo, y el CLR está dentro de sus derechos para producir ese comportamiento. Eso incluye ambos bloques que se ejecutan finalmente y no bloques que se ejecutan finalmente

Supongamos que no hay una excepción no capturada y se lanza una excepción, y finalmente hay un bloque en el camino hacia la captura. ¿Está garantizado que el bloque finally se ejecutará? No Hay muchas cosas que podrían impedir que finalmente el bloque se ejecute en un programa legal. Por ejemplo, otro filtro de bloque o excepción finalmente podría ir a un bucle infinito o fallar rápidamente, cualquiera de los cuales evitaría que se ejecutara el bloque final. Si usted ABSOLUTAMENTE POSITIVAMENTE debe ejecutar un código de limpieza, entonces debe estar investigando las Regiones de Ejecución Restringidas. (No sé cómo funcionan; nunca tuve necesidad de aprender. Escuché que son difíciles).

Lo que se garantiza es que si el control deja un bloque protegido finalmente, el código se ejecutará finalmente . El código ejecutado durante los filtros de excepción no cuenta como que abandona el bloque, y fallar rápidamente no hace que el control del programa salga de un bloque, sino que el control del programa finaliza abruptamente. Obviamente, los bucles infinitos hacen que el control nunca salga de un bloque.

Supongo que en el caso de una excepción verdaderamente no manejada, el programa debería terminar de todos modos, de modo que una conexión / transacción de base de datos huérfana no debería ser un problema.

Si es un problema o no, no puedo decir. Pregúntele al autor de su base de datos.

Es muy probable que el programa se termine, aunque nuevamente observo que no es necesario que el CLR tenga ese comportamiento. Supongamos, por ejemplo, que hay un hilo que se sigue ejecutando mientras el CLR está tratando de averiguar si tiene un depurador instalado o no. El CLR está dentro de sus derechos de demorar arbitrariamente en darse cuenta de eso y, por lo tanto, dentro de sus derechos de mantener ese hilo en ejecución. Si lo hace o no, no lo sé. Lo que sí sé es que no me gustaría confiar en ninguno de los dos comportamientos.

Además, utiliza el ''Recuento de eventos AppDomain.CurrentDomain.UnhandledException como'' manejo ''

No Si eso funciona, hubo una excepción no controlada y el comportamiento del programa está definido por la implementación. Ese controlador de eventos debe usarse solo para hacer cosas como registrar el hecho de que el programa tiene un error.


Además de lo que escribió Lipper, tenga en cuenta que está escrito en MSDN ... En el try...finally :

Sin embargo, si la excepción no se maneja, la ejecución del bloque finally depende de cómo se desencadena la operación de desenrollamiento de la excepción. Eso, a su vez, depende de cómo esté configurada su computadora.

y

Por lo general, cuando una excepción no controlada finaliza una aplicación, no importa si el último bloque se ejecute o no.

y luego se explica que si pones un try... catch a un nivel "alto", entonces el try... finally interno try... finally se ejecutará.


Antes de Framework 4.0, las excepciones no manejadas lanzaron ''Microsoft .NET Error Reporting Shim'', que muestra el cuadro de diálogo que ofrece ''Depurar'' o ''Cerrar programa''. El shim permite que las aplicaciones .NET se cierren "limpiamente".

Comenzando con Framework 4.0 (por lo que puedo decir), las excepciones no manejadas dan como resultado que Windows inicie el Informe de errores de Windows (WER), que aparece como Informe de problemas de Windows en el Administrador de tareas. Esta aplicación muestra un cuadro de diálogo similar al de la simulación, pero adopta un enfoque más estricto para eliminar la aplicación, probablemente llamando a TerminateProcess o TerminateThread, lo que no permitiría que se ejecutara ningún otro código en el proceso de mal comportamiento.