c# - practices - ¿Está bien tragar todas las excepciones excepto las críticas en ciertos escenarios?
throw exception c# (6)
Hay ciertos escenarios en los que solo quiero llamar a un determinado método para hacer un trabajo y no me importa manejar todas las excepciones específicas que puede lanzar. En cambio, todo lo que realmente me importa es si el método tuvo éxito o no.
Proporcionaré un ejemplo de .NET / C #. Digamos que tengo un archivo que quiero copiar y todo lo que realmente me importa es si la operación de copia fue exitosa o no. Si la copia falló, no me importa si una excepción particular fue la excepción FileNotFoundException o una excepción IOException o "No hay suficiente espacio en el disco" o algo más ... Mi aplicación se moverá normalmente en ese caso, ya que esta operación no es crítica.
Así que la idea de cómo implementar esto es:
try
{
// try
System.IO.File.Copy(strFile, strFile + ".new");
}
catch (Exception ex)
{
// if critical exception then rethrow
if (IsCritical(ex))
throw;
// else just log and swallow...
Console.WriteLine("Failed to copy the file: " + ex.Message);
}
donde IsCritical (Exception ex) es un método auxiliar definido como:
public static bool IsCritical(Exception ex)
{
if (ex is OutOfMemoryException) return true;
if (ex is AppDomainUnloadedException) return true;
if (ex is BadImageFormatException) return true;
if (ex is CannotUnloadAppDomainException) return true;
if (ex is ExecutionEngineException) return true;
if (ex is InvalidProgramException) return true;
if (ex is System.Threading.ThreadAbortException)
return true;
return false;
}
Esta pregunta se basa en el siguiente artículo: Manejo de excepciones en C # con la regla "No capturar excepciones que no puede manejar" en mente
La idea es seguir las reglas principales de las mejores prácticas de manejo de excepciones: - no capturar Excepciones generales sin volver a generarlas - capturar solo las excepciones que sepa manejar - (en este caso, quiero manejarlas todas de la misma manera ... iniciando sesión y avanzando con la lógica de la aplicación).
Entonces, ¿es este un buen enfoque para el escenario dado? Si no, ¿por qué y qué sería mejor hacer?
Creo que respondiste tu pregunta. Es totalmente depende de su lógica de negocio. Pero en general, si quisiera "tragar" la excepción, pero solo por su tipo particular, como lo hizo otra vez.
Está bien tragar excepciones específicas en casos particulares, pero en la práctica depende del caso de uso.
Recomiendo manejar las excepciones, puede manejar y usar el evento AppDomain.UnhandledException para las excepciones no manejadas e informar al usuario sobre lo que sucedió.
Desde la perspectiva de la depuración, realmente no importa, siempre que tenga acceso al código, ya que puede habilitar la interrupción de todas las excepciones de tiempo de ejecución comunes en Visual Studio. (Depuración -> Excepciones -> Excepciones de Common Language Runtime -> Marque la casilla de verificación izquierda)
Nunca dependería de una lista de excepciones críticas, porque realmente no se sabe si la lista está completa.
Esta línea me preocupa un poco ...
Si la copia falló, no me importa si una excepción en particular fue la excepción FileNotFoundException o una excepción IOException "No hay suficiente espacio en el disco" o alguna otra cosa
No es tanto la excepción FNF, sino más " No hay suficiente espacio en el disco ", etc. - este es el tipo de excepciones que probablemente no quiera ignorar. La razón es que, si no hay suficiente espacio en el disco, en teoría, su aplicación finalmente fallará. Esta es en realidad una de las razones principales por las que no debería detectar excepciones generales porque efectivamente enmascara problemas más grandes como estos.
En una nota más general, y para responder a su pregunta más específicamente, está perfectamente bien detectar una excepción más general en la que está seguro de que no tendrá mayores implicaciones con su aplicación ni, como se mencionó anteriormente (y lo reitero para buena razón), no ocultará ningún problema más grande / más serio.
La razón por la que generalmente se recomienda no tragar excepciones es que puede ocultar errores. Por ejemplo, está haciendo otra cosa que no es hacer una File.Copy
: también está procesando cadenas ( strFile + ".new"
). Esto no se puede lanzar (excepto para OOM), pero si el cálculo fue más complejo, es posible que haya ocultado un error .
En este caso, probablemente debería mover todos los cálculos fuera del bloque try. Entonces está bien tragar cualquier excepción. Tengo la costumbre de registrarlos en caso de que todavía cometiera un error a pesar de ser cuidadoso.
La regla de no tragar innecesariamente es proteger al desarrollador de su propia falibilidad. Si está razonablemente seguro de que todo está bien, entonces no necesita seguir la regla.
Me sentiría inclinado a decir que cualquier excepción que provenga del código que usted no escribió, debe tratarse como una excepción crítica, ya que significa que el sistema que lanzó el error podría estar en un estado indefinido y, por lo tanto, cualquier operación posterior que usted realice. intento de que el sistema no puede garantizarse para tener éxito.
Por lo tanto, probablemente haría algo como:
try
{
System.IO.File.Copy(strFile, strFile + ".new");
//MyLibrary throws exception clases I defined so I know what they are all about
MyLibrary.SomeClass.DoSomething(strFile);
}
catch(ExceptionTypeIDefinedInMyLibraryWhichIKnowICanSafelyIgnore iex)
{
Console.WriteLine("Not to worry: "+ iex.Message);
}
catch (Exception ex)
{
//This absolute is not something I can handle. Log it and throw.
Log(ex); throw;
}
De esta manera, no puede ignorar las excepciones críticas, y solo puede lanzar un tipo específico de excepción desde sus propios subsistemas porque usted tiene el control de lo que lanzan.
Sin embargo, si realmente quisiera seguir el patrón que demostró, me inclino a darle la vuelta y solo tratar con las excepciones que sabe que puede manejar, y lanzar todo lo demás.
De esa manera, no se quemará cuando se OhMyGodThereAreZombiesInTheServer
una nueva excepción OhMyGodThereAreZombiesInTheServer
al BCL, nunca se sabe, podría suceder ...
es decir
try
{
// try
System.IO.File.Copy(strFile, strFile + ".new");
}
catch (Exception ex)
{
// if critical exception then rethrow
if (ICanHandleThis(ex))
{
Console.WriteLine("Failed to copy the file: " + ex.Message);
}
else
{
//step aside and let Dr McNinja deal with it
throw;
}
}
public static bool ICanHandleThis(Exception ex)
{
//I don''t care about these exceptions, they aren''t critical
//to my application for some reason.
return (ex is SomeTrivialExceptionTypeIDontCareAbout
|| ex is SomeOtherIgnorableExceptionType);
}
Puedes agregar varias declaraciones catch para el mismo intento:
try
{
//code here
}
catch (FileNotFoundException ex1)
{
//Do whatever you want
}
catch (IOException ex2)
{
//Do whatever you want
}
Sugiero manejar la excepción que no considera crítica y para todas las restantes solo haga una catch (Exception er){throw ;}
También Solo por esta excepción específica dos es suficiente solo para capturar una IOException
, porque IOException
es la clase primaria de FileNotFountException