Errores comunes de programación in.Net al manejar excepciones? [cerrado]


¿Cuáles son algunos de los errores más comunes que se han cometido al manejar excepciones?

Parece que el manejo de excepciones puede ser una de las cosas más difíciles de aprender a hacer "bien" en .Net. Especialmente teniendo en cuenta la respuesta actualmente #1 clasificada a Errores de programación comunes para los desarrolladores de. NET a evitar? está relacionado con el manejo de excepciones.

Esperemos que al enumerar algunos de los errores más comunes, todos podamos aprender a manejar mejor las excepciones.

Author: jColeson, 2010-05-21

14 answers

¿Cuáles son algunos de los errores más comunes que se han cometido al manejar excepciones?

Se me ocurren muchas cosas.

En Primer lugar, lea mi artículo sobre la clasificación de las excepciones en molesto, estúpido, fatal y exógenos:

Http://ericlippert.com/2008/09/10/vexing-exceptions /

Algunos errores comunes:

  • Fallo en el manejo de excepciones exógenas.
  • Falta de manejo de las molestias salvedad.
  • Construcción de métodos que arrojan excepciones irritantes.
  • Manejando excepciones que realmente no puede manejar, como excepciones fatales.
  • Manejo de excepciones que ocultan errores en su código; no maneje una excepción estúpida, corrija el error para que no se lance en primer lugar

  • Error de seguridad: fallo en el modo inseguro

    try
    {
      result = CheckPassword();
      if (result == BadPassword) throw BadPasswordException();
    }
    catch(BadPasswordException ex) { ReportError(ex); return; }
    catch(Exception ex) { LogException(ex); }
    AccessUserData();
    

    ¿Ves lo que pasó? Fallamos en el modo inseguro. Si CheckPassword lanzó NetworkDriverIsAllMessedUpException luego lo capturamos, lo registramos y accedimos a los datos del usuario independientemente de si la contraseña era correcta. Falla al modo seguro; cuando obtengas alguna excepción, asume lo peor.

  • Error de seguridad: producción de excepciones que filtran información sensible, directa o indirectamente.

    Esto no se trata exactamente de manejar excepciones en su código, se trata de producir excepciones que son manejadas por hostile codificar.

    Historia Divertida. Antes de que. NET 1.0 se enviara a los clientes, encontramos un error en el que era posible llamar a un método que lanzaba la excepción " el ensamblado que llamó a este método no tiene permiso para determinar el nombre del archivo C:\foo.txt". Gran. Gracias por avisarme. ¿Qué impide que dicho ensamblado capte la excepción e interrogue su mensaje para obtener el nombre del archivo? Nada. Lo arreglamos antes de embarcar.

    Ese es un problema directo. Un problema indirecto sería un problema que implementé en LoadPicture, en VBScript. Dio un mensaje de error diferente dependiendo de si el argumento incorrecto es un directorio, un archivo que no es una imagen o un archivo que no existe. Lo que significa que se podría utilizar como un navegador de disco muy lento! Al intentar un montón de cosas diferentes, podría construir gradualmente una imagen de qué archivos y directorios estaban en el disco duro de alguien. Las excepciones deben diseñarse de manera que si se manejan con código no confiable, que el código no aprende nada de la información privada del usuario de lo que sea que hicieron para causar la excepción. (LoadPicture ahora da mensajes de error mucho menos útiles.)

  • Error de seguridad y administración de recursos: Los manejadores que no limpian los recursos están esperando fugas de recursos. Las fugas de recursos se pueden usar como ataques de denegación de servicio por código de confianza parcial hostil que crea deliberadamente excepciones que producen situación.

  • Error de robustez: Los manejadores deben asumir que el estado del programa está mal a menos que manejen una excepción exógena específica. Esto es particularmente cierto en el caso de los bloques finally. Cuando estás manejando una excepción inesperada, es completamente posible e incluso probable que algo esté profundamente desordenado en tu programa. No tienes idea de si alguno de tus subsistemas está funcionando, y si lo están, si llamarlos hará que la situación sea mejor o peor. Concéntrate en registrar el error y guardar los datos del usuario si es posible y apagar tan limpiamente como sea posible. Supongamos que nada funciona bien.

  • Error de seguridad: las mutaciones temporales del estado global que tienen impactos en la seguridad deben deshacerse antes de se puede ejecutar cualquier código que pueda ser hostil. ¡El código hostil puede ejecutarse antes de que finalmente se ejecuten los bloques! Ver mi artículo sobre esto para detalles:

Http://blogs.msdn.com/ericlippert/archive/2004/09/01/224064.aspx

 44
Author: Eric Lippert,
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
2013-08-28 16:12:12

Re-lanzar excepciones como esta:

try 
{ 
   // some code here
}
catch(Exception ex)
{
   // logging, etc
   throw ex;
}

Esto mata el seguimiento de la pila, haciendo que sea mucho menos utilizable. La manera correcta de repensar sería así:

try 
{ 
   // some code here
}
catch(Exception ex)
{
   // logging, etc
   throw;
}
 25
Author: Adam Lear,
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
2010-05-21 16:51:31

Captura todas las excepciones cuando en muchos casos debe intentar capturar excepciones específicas:

try {
  // Do something.
} catch (Exception exc) {
  // Do something.
}

En lugar de:

try {
  // Do something.
} catch (IOException exc) {
  // Do something.
}

Las excepciones deben ordenarse de más específicas a menos.

 12
Author: Jay Riggs,
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
2010-05-21 16:55:00

Repensar una excepción con un mensaje sin sentido.

try
{
    ...
}
catch (Exception ex)
{
   throw new Exception("An error ocurred when saving database changes").
}

No creerás la frecuencia con la que veo código como este ejecutándose en producción.

 10
Author: CARLOS LOTH,
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
2010-05-21 17:15:01

Nadie está hablando de ver bloques de captura vacíos como estos....

 try{  
      //do something
    }
catch(SQLException sqex){  
        // do nothing  
    }

Tampoco utilice nunca el manejo de excepciones para crear flujos de métodos alternativos...

 try{  
     //do something  

 }catch(SQLException sqex){  

     //do something else  
 }
 9
Author: Srikar Doddi,
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
2010-05-21 18:00:30

No usar using en IDisposable objetos:

File myFile = File.Open("some file");
callSomeMethodWhichThrowsException(myFile);
myFile.Close();

Miarchivo no se cierra hasta que miarchivo del finalizador se llama (el cual puede ser nunca) porque se produce una excepción antes de myFile.Close() fue llamado.

La manera correcta de hacer esto es

using(File myFile = File.Open("some file"))
{
    callSomeMethodWhichThrowsException(myFile);
}

Esto se traduce por el compilador en algo como:

File myFile = File.Open("some file");
try
{
    callSomeMethodWhichThrowsException(myFile);
}
finally
{
    if(myFile != null)
        myFile.Dispose(); //Dispose() calls Close()
}

Así que el archivo se cierra incluso ante excepciones.

 7
Author: BlueRaja - Danny Pflughoeft,
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
2010-05-21 18:34:27

Olvídese de establecer la excepción interna al repensar una excepción atrapada

try
{
    ...
}
catch (IOException ioException)
{
    throw new AppSpecificException("It was not possible to save exportation file.")
    // instead of
    throw new AppSpecificException("It was not possible to save exportation file.", ioException);
}

Cuando publiqué esta respuesta, me olvido de mencionar que siempre debemos considerar cuándo incluir excepciones internas o no debido a razones de seguridad. Como Eric Lippert señaló en otra respuesta para este tema, algunas excepciones pueden proporcionar información confidencial sobre los detalles de implementación del servidor. Por lo tanto, si el llamante que manejará la excepción no es de confianza, no lo es una buena idea incluir la información de la excepción interna.

 6
Author: CARLOS LOTH,
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
2017-05-23 12:07:55

Captura vacía:

//What's the point?
catch()
{}

Repensar:

//Exceptions are for *adding* detail up the stack
catch (Exception ex)
{throw ex;}
 4
Author: Dave Swersky,
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
2010-05-21 16:51:12

Asumir una excepción que cubre muchos escenarios era algo específico. Un escenario de la vida real era una aplicación web donde el manejo de excepciones siempre asumía que todos los errores eran tiempos de espera de la sesión y se registraban e informaban de todos los errores como tiempos de espera de la sesión.

Otro ejemplo:

try
{
     Insert(data);
}
catch (SqlException e)
{
   //oh this is a duplicate row, lets change to update
   Update(data);
}
 3
Author: MatthewMartin,
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
2010-05-21 17:17:35

Para registrar la Excepción.Mensaje en lugar de Excepción.toString ()

Muchas veces, veo el registro de código solo el mensaje de excepción, mientras que debería registrar el retorno del método toString. toString proporciona mucha más información sobre la excepción que el Mensaje. Incluye información como excepción interna y seguimiento de pila además del mensaje.

 3
Author: CARLOS LOTH,
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
2010-05-21 17:21:12

Tratando de atrapar OutOfMemoryException o StackOverflowException - estos conducen a un apagado del tiempo de ejecución, por lo tanto a la manera de atraparlos desde dentro del mismo Proceso (o incluso desde el CLR en su conjunto?)

OutOfMemoryException: La excepción que se lanza cuando no hay suficiente memoria para continuar la ejecución de un programa.

" A partir de la versión 2.0 de. NET Framework, un objeto StackOverflowException no puede ser capturado por un bloque try-catch y el proceso correspondiente se termina por defecto. En consecuencia, se aconseja a los usuarios escribir su código para detectar y evitar un desbordamiento de pila."

 1
Author: Michael Stum,
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
2010-05-21 17:44:43

No se pueden detectar posibles excepciones dentro de un controlador de capturas. Esto puede hacer que la excepción equivocada se propague hacia arriba.

Por ejemplo:

try
{
    DoImportantWork();
}
catch
{
    Cleanup();        
    throw;
}

¿Qué sucede si Cleanup() lanza una excepción? No querrás ver una Excepción que apunte al método Cleanup() en este controlador de capturas. Quieres el error original. Puede intentar registrar el error de limpieza, pero incluso su código de registro necesita manejo de excepciones para evitar lanzar excepciones.

try
{
    DoImportantWork();
}
catch
{
    try
    {
        Cleanup();        
    }
    catch
    {
        // We did our best to clean up, and even that failed.
        // If you try to log this error, the logging may throw yet another Exception.
    }
    throw;
}
 1
Author: Paul Williams,
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
2010-05-21 18:47:55

Incorrecto

try
{
   // Do something stupid
}
catch
{
   // ignore the resulting error because I'm lazy, and later spend
   // a week trying to figure out why my app is crashing all over
   // the place.
}

Mejor

try
{
    /// do something silly.
}
catch (InvalidOperationException ex)
{
    /// respond, or log it.
}
catch (Exception e)
{
    /// log it.
}
 0
Author: 3Dave,
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
2010-05-21 17:01:12

Usando excepciones para el control de flujo normal. Las excepciones deben ser excepcionales. Si es una operación buena / esperada, use valores de retorno, etc.

 0
Author: Donnie,
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
2010-05-21 18:34:21