una que practices handling exceptions excepción example custom best c# .net exception exception-handling

que - throw custom exception c#



¿Son estos try/catch''es equivalentes? (3)

Guión

Tengo un método que hace la operación de base de datos (digamos). Si durante esa operación se produce una excepción, solo quiero lanzar esa excepción a la persona que llama. No quiero hacer ninguna tarea específica en el bloque catch, asumiendo que la persona que llama hará lo que quiera con esa excepción. En este escenario, ¿cuál es la técnica apropiada de manejo de excepciones?

try { // Some work that may generate exception } catch(Exception) { throw; } finally { // Some final work }

¿Lo anterior es equivalente a la siguiente prueba / captura / finalmente?

try { // Some work that may generate exception } catch { throw; } finally { // Some final work }

¿Lo anterior es equivalente al siguiente intento / finalmente?

try { // Some work that may generate exception } finally { // Some final work }

¿Cuál es mejor que el otro? ¿Cuál debería ser usado?


Ambas declaraciones try / catch son equivalentes en el sentido de que están volviendo a lanzar la excepción original que se detectó. Sin embargo, la catch vacía es más amplia (como ya dijo Venemo, capturando excepciones no administradas). Si desea catch una excepción y capturarla en una variable, puede usarla para el registro o puede throw una nueva excepción al pasar la excepción original como un argumento, lo que la convierte en la "excepción interna" .

El finally va a funcionar igual independientemente.

Cuál se debe usar, en un escenario en el que no necesitamos una excepción de registro y asumimos explícitamente que la persona que llama manejará la excepción que se genera, como escribir en el flujo de archivos o enviar correos electrónicos.

Si la persona que llama manejará la excepción y no necesita registrar la ocurrencia de la excepción en este nivel, entonces no debería detectar nada. Si la persona que llama manejará una excepción que se está lanzando, no hay necesidad de atrapar una excepción solo para volver a lanzarla.

Razones válidas para atrapar una excepción que se volverá a lanzar:

  • throw new Exception("WTF Happened", ex); // Use as inner exception
  • Excepción de registro
  • Usa un bloque finally para ejecutar algún código de limpieza.

No, no son equivalentes. Pueden ser equivalentes en algunos casos, pero la respuesta general es no.

Diferentes tipos de bloques de catch

bloque de catch con un tipo de excepción especificado

Lo siguiente solo detectará las excepciones administradas que heredan de System.Exception y luego ejecuta el bloque finally , que ocurrirá independientemente de si se lanzó una excepción o no.

try { // Some work that may generate exception } catch (Exception) { throw; } finally { // Some final work }

bloque de catch sin un tipo de excepción especificado

El siguiente bloque catch sin un especificador de tipo también detectará excepciones no administradas que no están necesariamente representadas por un objeto System.Exception administrado, y luego ejecuta el bloque finally , que ocurrirá independientemente de si se lanzó una excepción o no.

try { // Some work that may generate exception } catch { throw; } finally { // Some final work }

finally bloque sin un bloque de catch

Si no tiene un bloque catch en absoluto, su finally se ejecutará independientemente de si se produjo o no una excepción.

try { // Some work that may generate exception } finally { // Some final work }

¿Cuándo son equivalentes?

En caso de que su bloque catch no especifique una excepción y solo contenga el throw; declaración, los dos últimos son de hecho equivalentes. En caso de que no te preocupen las excepciones no administradas y tu bloque catch solo contenga el throw; declaración, los tres pueden considerarse equivalentes.

Notas

Una nota sobre el throw

Las siguientes dos piezas de código contienen una sutil diferencia. Este último volverá a lanzar la excepción, lo que significa que volverá a escribir el seguimiento de pila de la excepción, por lo que definitivamente no son equivalentes:

catch (Exception e) { throw; }

Y

catch (Exception e) { throw e; }

En caso de que utilice finally un IDisposable , los siguientes dos códigos son casi equivalentes, pero con algunas diferencias sutiles:

  • Cuando el objeto es nulo, la instrucción using no le dará una NullReferenceException
  • Cuando se utiliza la técnica try - finally , la variable permanece dentro del alcance, aunque no se recomienda utilizar ningún objeto después de que se haya eliminado. Sin embargo, todavía puede reasignar la variable a otra cosa.

    Algo obj = nulo; intente {obj = new Something () // Haga algo} finalmente {obj.Dispose (); }

Y

using (var obj = new Something()) { // Do something }


Tienes algunas buenas respuestas hasta ahora, pero hay una diferencia interesante que no mencionaron hasta ahora. Considerar:

try { ImpersonateAdmin(); DoWork(); } finally { RevertImpersonation(); }

vs

try { ImpersonateAdmin(); DoWork(); } catch { RevertImpersonation(); throw; } finally { RevertImpersonation(); }

Supongamos que DoWork lanza.

Ahora la primera pregunta que nos ocupa es "¿existe un bloque catch que pueda manejar esta excepción?", Porque si la respuesta es "no", entonces el comportamiento del programa está definido por la implementación . El tiempo de ejecución puede optar por finalizar el proceso inmediatamente, puede elegir ejecutar los bloques finally antes de que finalice el proceso, puede optar por iniciar un depurador roto en el punto de la excepción no controlada, puede elegir hacer lo que quiera. Los programas con excepciones no manejadas están autorizados a hacer cualquier cosa.

Así que el tiempo de ejecución comienza a buscar un bloque catch. No hay ninguno en esta declaración de prueba, por lo que busca la pila de llamadas. Supongamos que encuentra uno con un filtro de excepción. Necesita saber si el filtro permitirá que se maneje la excepción, de modo que el filtro se ejecute antes de revertir la suplantación . Si el filtro hace algo accidental o deliberadamente que solo un administrador puede hacer, ¡tendrá éxito! Esto podría no ser lo que quieres.

En el segundo ejemplo, el catch atrapa la excepción inmediatamente, revierte la suplantación, lanza, y ahora el tiempo de ejecución comienza a buscar un bloque catch para manejar el relanzamiento. Ahora, si hay un filtro, se ejecuta después de revertir la suplantación. (Y, por supuesto, finalmente vuelve a aparecer; supongo que revertir la personificación es idempotente aquí).

Esta es una diferencia importante entre estos dos fragmentos de código. Si está absolutamente absolutamente prohibido que cualquier código vea el estado global que fue desordenado por el intento y que fue limpiado por el finalmente, entonces hay que atraparlo antes de finalmente. "Finalmente" no significa "inmediatamente", significa "eventualmente".