Qué problema tiene este código? (III)

Continuando con la línea de posts relacionada con problemas potenciales con los que los programadores .NET deben tener cuidado, aquí va uno al que, si se tratara de un film, le añadiríamos la coletilla “basado en una historia real”: deriva directamente de un bug que encontré hace unos días revisando el código de un proyecto heredado.

Suponga que tenemos una clase como la siguiente:

public class Customer
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    public Customer(string name)
    {
        Id = Guid.Empty;
        Name = name;
    }

    public void Persist()
    {
        // Here the object is persisted to the database
        // And ‘Id’ field is assigned a value if it is Empty
    }

    // …More class’ definition…

    public void Action()
    {
        if (Id == null)  // The bug is here!
            Persist();
        // The action’s code…
    }
}

¿Ve dónde está el problema? Seguramente de manera inconsciente, el programador comparó el Guid (que, como sabemos, es un tipo valor) con null en vez de con Guid.Empty. Como resultado, el objeto no se persiste si no lo estaba anteriormente (la comparación produce siempre falso).

En este excelente post, miembros del equipo de C# explican claramente por qué la comparación (de igualdad o desigualdad) de un tipo valor con null produce una advertencia y no un error; básicamente, debido a la posibilidad de promoción (lifting) de los tipos valor a sus correspondientes tipos valor anulables. Con eso estoy totalmente de acuerdo; con lo que no lo estoy del todo es con la asignación a este problema potencial del nivel de advertencia 2, con lo que pasará totalmente desapercibido en caso de que el proyecto se compile con nivel 1.

Como siempre, ¡queda advertido!

Excepciones más o menos fatales

“The world weighs on my shoulders
But what am I to do?”
(“Distant Early Warning”, Rush, 1984)

Hace unos días, mi colega y amigo Fernando Chapa, sin duda uno de los mejores programadores con los que he tenido la suerte de trabajar, llamó mi atención sobre una clase base que se me antoja poco conocida (tal vez por poco documentada), aunque forma parte de la librería de clases de .NET desde la versión 2.0: System.WarningException.

WarningException hereda directamente de Exception; la idea que subyace es la de que las excepciones de esta clase o cualquiera de sus descendientes deben ser tratadas como advertencias más que como errores. En particular, si una aplicación de consola o escritorio no maneja una excepción de este tipo, en lugar del más familiar diálogo:

el usuario recibirá uno como éste (el mensaje es el asociado a la excepción, claro):

 

Me pareció interesante llamar aquí la atención sobre la existencia de esta clase no por el hecho de cómo reacciona .NET en el caso de que una excepción de este tipo no sea manejada, puesto que toda aplicación que se precie debería implementar un gestor de excepciones global basado en los mecanismos que ofrece para ello .NET (Application.ThreadException en Windows Forms, Page.ErrorPage en ASP.NET, etc.), sino por el interés que podría tener para aquellos que diseñan librerías de clases con sus propias clases de excepciones.


El bit nostálgico: WarningException me recordó a una clase de excepción que ofrecía (perdón, que aún ofrece) Delphi, llamada EAbort y conocida como “la excepción silenciosa”. Si esta excepción se produce (casi siempre provocada por el propio programador mediante una llamada al método predefinido Abort) y llega sin ser tratada al nivel más externo de la pila de llamadas, el sistema “se la traga” de manera silenciosa. Tal vez en alguna próxima versión de .NET veamos una clase así (heredera, probablemente, de WarningException :-).


Pop/Rock tip: Rush es, probablemente, la banda de rock canadiense más importante de todos los tiempos, con una muy exitosa carrera que abarca cinco décadas, a lo largo de las cuales se han reinventado a sí mismos varias veces de una manera muy digna, y veintitantos discos de oro. Mis discos favoritos de Rush corresponden a la época en que hacían un rock más progresivo: “A Farewell to Kings” (1977), “Hemispheres” (1978), “Permanent Waves” (1980) y “Moving Pictures” (1981). El tema que hemos mencionado aquí pertenece al disco “Grace Under Pressure” de 1984, época en la que ya habían adoptado un estilo algo más comercial.