Capítulo 6: Instrucciones para provocar y controlar errores

Visual Studio .NET 2003
Publicado: 26 de junio de 2006

Patterns & Practices
Microsoft Corporation
Diciembre de 2002

imagen

http://msdn.microsoft.com/practices/

En esta página

Capítulo 6: Instrucciones para provocar y controlar errores Capítulo 6: Instrucciones para provocar y controlar errores

Capítulo 6: Instrucciones para provocar y controlar errores

En las reglas siguientes se describen las instrucciones para provocar y controlar errores:

  • Todas las rutas de código que generan una excepción deben proporcionar un método para comprobar el funcionamiento correcto sin que se inicie una excepción. Por ejemplo, para evitar una excepción FileNotFoundException, se puede invocar File.Exists; aunque esto puede no ser siempre posible, pero el objetivo consiste en que no se inicien excepciones en condiciones de ejecución normales.

  • Termine los nombres de la clase Exception con el sufijo Exception como en el siguiente ejemplo

[Visual Basic]

Public Class FileNotFoundException 
   Inherits Exception 
   ' Implementation code goes here.
End Class

[C#]

public class FileNotFoundException : Exception 
{
   // Implementation code goes here.
}
  • Al crear clases de excepciones, use los constructores comunes que se muestran en el siguiente ejemplo de código.

[Visual Basic]

Public Class XxxException
   Inherits ApplicationException 
   
   Public Sub New()
      ' Implementation code goes here.
   End Sub

   Public Sub New(message As String)
      ' Implementation code goes here.
   End Sub

   Public Sub New(message As String, inner As Exception)
      ' Implementation code goes here.
   End Sub

   Public Sub New(info As SerializationInfo, context As StreamingContext)
      ' Implementation code goes here.
   End Sub
End Class

[C#]

public class XxxException : ApplicationException 
{
   public XxxException() {... }
   public XxxException(string message) {... }
   public XxxException(string message, Exception inner) {... }
   public XxxException(SerializationInfo info, StreamingContext context) {...}
}
  • En la mayoría de los casos, utilice los tipos de excepción predefinidos. Defina nuevos tipos de excepciones sólo para escenarios en los que espera que los usuarios de la biblioteca de clases detecten las excepciones de este nuevo tipo y realicen una acción mediante programación en función del tipo de excepción. Esto es en vez de analizar la cadena de la excepción, lo cual tendría un impacto negativo en el rendimiento y en el mantenimiento.

Por ejemplo, tiene más sentido definir una excepción FileNotFoundException porque puede ocurrir que el programador decida crear el archivo que falta. No obstante, no es habitual administrar una excepción FileIOException en el código.

  • No derive todas las excepciones nuevas directamente de la clase base SystemException. Cuando cree nuevas excepciones en espacios de nombres System, herede sólo de SystemException. Cuando cree nuevas excepciones en otros espacios de nombres, herede de ApplicationException.

  • Agrupe las nuevas excepciones derivadas de la clase base SystemException o ApplicationException por espacio de nombres. Por ejemplo, todas las excepciones System.IO se agrupan bajo IOException (derivada de SystemException) y todas las excepciones Microsoft.Media se podrían agrupar bajo MediaException (derivada de ApplicationException).

  • Utilice una cadena de descripción localizada en cada excepción. Cuando el usuario vea un mensaje de error, se derivará de la cadena de descripción de la excepción iniciada y nunca de la clase exception.

  • Genere mensajes de error gramaticalmente correctos y con puntuación. Cada frase de la cadena de descripción de una excepción debe terminar con un punto. El código que normalmente muestra un mensaje de excepción al usuario, no tiene que tratar el caso en el que un programador se olvida de incluir un punto final.

  • Proporcione las propiedades de la excepción para el acceso mediante programación. Incluya información adicional (además de la cadena de descripción) en una excepción sólo cuando haya un escenario mediante programación en el que la información adicional es útil. Serán contadas las ocasiones en las que necesitará incluir información adicional en una excepción.

  • No exponga información protegida en mensajes de excepciones. Datos como las rutas de acceso del sistema de archivos local se consideran información privilegiada. Código malicioso podría usar esta información para recopilar información de usuario privada del equipo.

  • No utilice excepciones en errores normales o esperados, o en el flujo normal de control.

  • Debe devolver el valor null en los casos de error sumamente habituales. Por ejemplo, un comando File.Open devuelve una referencia null si no encuentra el archivo, pero inicia una excepción si el archivo está bloqueado.

  • Diseñe las clases de forma que durante su uso normal nunca se inicie una excepción. En el siguiente ejemplo de código, una clase FileStream expone otra forma de determinar si se ha llegado al final del archivo para evitar que se inicie una excepción si el programador lee más allá del final del archivo.

[Visual Basic]

Class FileRead 
   Sub Open() 
      Dim stream As FileStream = File.Open("myfile.txt", FileMode.Open)
      Dim b As Byte

      ' ReadByte returns -1 at end of file.
      While b = stream.ReadByte() <> true
         ' Do something.
      End While
   End Sub
End Class

[C#]

class FileRead 
{
   void Open() 
   {
      FileStream stream = File.Open("myfile.txt", FileMode.Open);
      byte b;

      // ReadByte returns -1 at end of file.
      while ((b = stream.ReadByte()) != true) 
      {
         // Do something.
      }
   }
}
  • Inicie la excepción InvalidOperationException si la llamada a un método o a un descriptor de acceso set no es apropiada dado el estado actual del objeto.

  • Inicie una excepción ArgumentException o genere una excepción derivada de esta clase si se pasan o se detectan parámetros no válidos.

  • Tenga en cuenta que el seguimiento de la pila comienza en el punto de inicio de una excepción, y no en el punto en el que se haya creado con el operador new. Considere esto cuando decida donde iniciar una excepción.

  • Utilice los métodos de generador de excepciones. Es normal que una clase inicie la misma excepción desde distintos lugares de su implementación. Para evitar el código repetitivo, utilice los métodos auxiliares que crean la excepción y la devuelven utilizando el operador new. En el siguiente ejemplo de código se muestra cómo implementar un método auxiliar.

[C#]

class File 
{
   string fileName;  
   public byte[] Read(int bytes) 
   {
      if (!ReadFile(handle, bytes))
            throw NewFileIOException();
   }
   
   FileException NewFileIOException() 
   {
      string description = 
         // Build localized string, include fileName.
      return new FileException(description);
   }
}
  • Inicie excepciones en lugar de devolver un código de error o HRESULT.

  • Inicie la excepción más específica posible.

  • Genere un texto de mensaje descriptivo de las excepciones para el programador.

  • Establezca todos los campos en la excepción que utilice.

  • Utilice excepciones internas (excepciones encadenadas). Sin embargo, no detecte ni reinicie las excepciones a menos que agregue más información o cambie el tipo de excepción.

  • No cree métodos que inicien NullReferenceException o IndexOutOfRangeException.

  • Realice la comprobación de argumentos en miembros protegidos (familia) y en miembros internos (ensamblado). Indique claramente en la documentación si el método protegido no realiza una comprobación de argumentos. A menos que se indique lo contrario, suponga que se realiza la comprobación de argumentos. No obstante, si no se realiza esta comprobación puede que el rendimiento mejore.

  • Limpie cualquier efecto secundario producido al iniciar una excepción. Los llamadores deben suponer que no hay efectos secundarios cuando una función inicia una excepción. Por ejemplo, si un método Hashtable.Insert inicia una excepción, el llamador puede asumir que el elemento especificado no se ha agregado al método Hashtable.

Tipos de excepciones estándar

En la tabla siguiente se incluyen las excepciones estándar que proporciona el tiempo de ejecución y las condiciones para las que deberá crear una clase derivada.

Tipo de excepción

Tipo base

Descripción

Ejemplo

Exception

Object

Clase base de todas las excepciones.

Ninguno (utilice una clase derivada de esta excepción).

SystemException

Exception

Clase base de todos los errores que genera el motor de tiempo de ejecución

Ninguno (utilice una clase derivada de esta excepción).

IndexOutOfRangeException

SystemException

La inicia el motor de tiempo de ejecución sólo cuando no se indiza correctamente una matriz.

Indizar una matriz fuera del intervalo válido:

arr[arr.Length+1]

NullReferenceException

SystemException

La inicia el motor de tiempo de ejecución sólo cuando se hace referencia a un objeto nulo.

object o = null;
o.ToString();

InvalidOperationException

SystemException

La inician los métodos que se encuentran en un estado no válido.

Llamar a

Enumerator.GetNext()

después de eliminar un

Item

de la colección subyacente.

ArgumentException

SystemException

Clase base de todas las excepciones de argumento.

Ninguno (utilice una clase derivada de esta excepción).

ArgumentNullException

ArgumentException

La inician los métodos que no permiten que un argumento sea nulo.

String s = null;
"Calculate".IndexOf (s);

ArgumentOutOfRangeException

ArgumentException

La inician métodos que comprueban que los argumentos
.............................. están en un intervalo dado.

String s = "string";
s.Chars[9];

ExternalException

SystemException

Clase base........................para excepciones que se generan o que tienen como destino entornos fuera del motor de ejecución.

Ninguno.......................(utilice una clase derivada de esta excepción).

COMException

ExternalException

Excepción que encapsula la información Hresult de COM.

Se usa en la interoperabilidad COM.

SEHException

ExternalException

Excepción que encapsula la información de control estructurado de excepciones Win32.

Se utiliza en la interoperabilidad de código no administrado.

Excepciones de contenedor

Los errores que se generan en el mismo nivel que un componente deben iniciar una excepción descriptiva para los usuarios de destino. En el siguiente ejemplo de código, el mensaje de error está destinado a los usuarios de la clase TextReader que intenten leer los datos de una secuencia.

Public Class TextReader   
   Public Function ReadLine() As String
      Try
         ' Read a line from the stream.
      Catch e As Exception
         Throw New IOException("Could not read from stream", e)
      End Try
   End Function 
End Class

public class TextReader
{
   public string ReadLine()
   {
      try
      {
         // Read a line from the stream.
      } 
      catch (Exception e)
      {
         throw new IOException ("Could not read from stream", e);
      }
   }
}

Instrucciones de diseño para programadores de bibliotecas de clases

Mostrar: