Normas para la creación de Excepciones propias en .NET

Cuando el código de nuestro programa produce un error o una situación no esperada que se traduce en un fallo se produce una excepción.



.NET Framework ofrece gestión estructurada de excepciones, es decir, que podemos gestionar las excepciones de manera jerárquica en nuestro código, capturándolas en la rutina que las produce o en cualquier otro punto de la pila de llamadas de ésta (es decir, las excepciones «convergen» hacia los niveles superiores de la pila).


La estructura Try-Catch-Finally (VB) o try-catch-finally (C#) nos permite gestionar las excepciones dentro del bloque «catch» especificando el tipo concreto de excepción que queremos gestionar, pudiendo así ser lo más específicos posible a la hora de hacerlo. Por ello la plataforma ofrece multitud de tipos de excepciones especializadas para indicar situaciones concretas: división por cero, argumentos no válidos, error de I/O, etc… Y también nos permite crear nuestras propias excepciones y lanzarlas con throw.


Así podemos generar excepciones propias para responder ante situaciones controladas por nuestro código o notificar situaciones al código que haga uso de nuestras funciones. Esto último contrasta enormemente con la programación tradicional en otros lenguajes, en los que para marcar el éxito o fracaso de ejecutar una determinada función se solían usar valores devueltos por las propias funciones (por ejemplo, si devuelve un 0 es que todo ha ido bien, pero en caso contrario devuelvo un numerito para indicar el error). Si no me crees fíjate en la API de Windows por ejemplo, que es un infierno con estas cosas 🙂


Eso es una mala práctica y gracias a los dioses se ha terminado por virtud de la gestión estructurada de excepciones. Y esto, algunos programadores «con solera» (o sea, viejos), lo tenemos muy a flor de piel ;-))


FatalExceptionTatoo


Pero… ¿Cómo genero mis propias excepciones?


Las excepciones son clases normales y corrientes que heredan de una clase base especial de la plataforma: Exception.


Por lo tanto podemos crear nuevas excepciones que hereden de otras y adaptarlas así a nuestras necesidades. Lo habitual sin embargo es heredar directamente de la clase base Exception mencionada.


Lo único que debemos tener en cuenta a la hora de crear nuestras propias excepciones son algunas convenciones que debemos seguir (no son obligatorias, pero siempre se hace así por convención para facilitar a otros programadores el trabajo):



1.- Termina el nombre de tu clase de excepción personalizada con el sufijo Exception.
2.- Haz que la excepción sea serializable. Si heredas de Exception ya no lo tienes que hacer tú.
3.- Implementa los tres constructores básicos: sin parámetros, con un mensaje como parámetro y un tercero con posibilidad de pasar una excepción interna anidada también. Insisto, no es necesario, pero sí recomendable.


Es muy fácil. Por ejemplo, imagin¡emos que queremos crear una excepción personalizada para señalar que un valor no puede ser negativo (por poner un ejemplo básico). La definición de una clase excepción para gestionar esta situación sería:

public class ValorNegativoException : Exception
{
public ValorNegativoException() : base(«No se admite un valor negativo») //Este es el mensaje por defecto, asignado a la clase base
{
}

public ValorNegativoException(string Mensaje) : base(Mensaje)
{
}

public ValorNegativoException(string Mensaje, Exception anidada) : base(Mensaje, anidada)
{
}

}


¡Listo!


Ahora ya podemos lanzar una excepción de este tipo usando la instrucción throw, así por ejemplo:

ValorNegativoException miExcep = new ValorNegativoException(«No puedes usar valores negativos. ¡En qué piensas! :-)»);
throw miExcep;

Y capturarla de la manera habitual dentro de un catch, ya que es una excepción normal como las propias de .NET.


¡Espero que te resulte útil!

Sin categoría

6 thoughts on “Normas para la creación de Excepciones propias en .NET

  1. «Copio y pego» el resumen de «Normativa de Desarrollo» para la creación de tipos de Excepciones que suelo instaurar en mis equipos de desarrollo, añaden a lo que mencionas la capacidad de Serialización de excepciones, más allá del ApplicationDomain donde se lanzan ( necesario a menudo ) y alguna cosa más como el añadir alguna propiedad descriptiva a la excepción más allá del Message de la clase base:

    – Evitar las jerarquías de clases de excepciones profundas. Si un tipo de excepción no va a tener un tratamiento especial debería utilizarse otro más general.

    – Cuando se hace necesaria una excepción a medida:
    a. Tratar de derivarla desde ApplicationException
    b. Siempre implementar el patrón para construcción de excepciones:

    public MyCustomException(): base();
    public MyCustomException (string message): base(message);
    public MyCustomException (string message,
    Exception innerException): base(message, innerException);
    protected MyCustomException (SerializationInfo info, StreamingContext context)

    c. Siempre implementar la serialización :
    o Añadir el atributo de clase [Serializable] siempre,
    o Si se añaden propiedades nuevas a la excepción:
    -> Sobrescribir el método GetObjectData de la interfaz ISerializable que Exception implementa para incluir las nuevas propiedades
    -> Sobrescribir el método ToString()para incluir las nuevas propiedades
    d. Las propiedades deben ser de sólo lectura.

    – Al relanzar una excepción tras haber capturado otra, pasar la original como InnerException para mantener el árbol de excepciones y la pila interna de llamadas, salvo que por motivos de seguridad no se quiera propagar más allá los detalles.

    – Evitar hacer uso de la nueva propiedad Exception.Data en aquellas excepciones que vayan a ser serializadas, debido a que esta propiedad no es serializable en la mayoría de los formatos y según el tipo de serialización puede lanzar una excepción o ser ignorada [.NET 2.0]

  2. Hola Pablo (no somos familiares ¡¿no?):

    Gracias por el aporte a mayores. Yo no pretendía ir tan lejos, sino dar unas orientaciones básicas de cómo crear tus propias excepciones. Pero lo tuyo viene muy bien 🙂

    Saludos,

    JM

  3. No que yo sepa, aunque alguna vez me han preguntado si era familiar tuyo 😉

    La idea era ampliar tu post… pero como siempre… es más «rápido copiar y pegar» 😉

    Ahora que lo releeo, hoy en día se supone que esta regla ya no aplica.. alguna clase del Framework deriva de ApplicationException e invalida el diseño original.. aún así yo prefiero partir de ella:

    a. Tratar de derivarla desde ApplicationException

  4. Hola Pablo,

    una apreciación respecto a derivar de ApplicationException…

    Copio literalmente: «If you are designing an application that needs to create its own exceptions, you are advised to derive custom exceptions from the Exception class. It was originally though that custom exceptions should derive from the ApplicationException class; however in practice this has not been found to add significant value. For more information, see Best Practices for Handling Exceptions.»

    En otro orden de cosas, según lo que se dice en el libro Framework Design Guidelines , System.ApplicationException es una clase que debería no formar parte de .NET Framework (porque es redundante). Tanto es así, que los autores de guías y patrones consideran a ApplicationException «carente de valor».

    En mi caso derivo de Exception.

    A continuación pongo unos enlaces:
    http://blogs.msdn.com/b/kcwalina/archive/2006/06/23/644822.aspx
    http://blogs.msdn.com/b/kcwalina/archive/2006/07/05/657268.aspx
    http://msdn.microsoft.com/en-us/library/system.applicationexception.aspx (mirar los comentarios finales)
    – Libro Framework Design Guidelines http://www.amazon.com/dp/0321246756/?tag=stackoverfl08-20

  5. Gracias Jorge, eso es justo lo que decía, que la regla de derivar de ApplicationException había pasada de recomendada a «redundante» en el Design Guidelines.

    Por lo que recuerdo de una conferencia de Kristoff Cwalina(uno de los autores), el motivo es que alguna excepción del Framework deriva de ella y con eso ha perdido el significado de distinguir claramente si es una excepción lanzada por el framework o no.

    PD: A ver si recupero mi usuario registrado… el reCaptcha es mortal para bots y humanos ….

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *