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á unaNullReferenceException
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".