La sentencia switch en C# 7.0 (y 2)

“It never rains in California,
But girl, don’t they warn ya,
It pours, man, it pours…”
Albert Hammond, It Never Rains in Southern California (1972)

Parte 1

En nuestra entrega anterior hablamos sobre las nuevas posibilidades de la sentencia switch, y en particular las relacionadas con la utilización de los tres tipos de patrones soportados por C# 7.0 en las cláusulas case, que mencionamos por primera vez aquí. En dicha última entrega nos quedó pendiente hablar sobre la utilización en el marco de las sentencias switch del tercer tipo de patrones disponible: los patrones var.

De manera similar a lo que ocurre cuando se les usa en una sentencia if, estos patrones casan incondicionalmente, y simplemente asignan el valor de la expresión de switch a la variable asociada, que será del mismo tipo de la expresión:

    switch (obj)
    {
        case var x:
            Console.WriteLine($”Type is {x.GetType().FullName});
            break;
    }

Como mismo dijimos entonces, no parece fácil encontrar una situación práctica donde la utilidad del uso de esta construcción sea evidente. Al menos, no he visto ninguno todavía en ninguno de los artículos que he leído al respecto (incluyendo los de MSDN donde se describe la característica). Pero ya sabemos que la vida es más rica que cualquier referente en el que la queramos enmarcar.

Algunas de las fuentes que he consultado sugieren que el uso de este patrón gana en posibilidades si se le combina con la otra novedad incorporada a la sentencia switch en C# 7.0: la cláusula when, que hace posible adosar una condición a una cláusula case, como se hace desde hace mucho tiempo en Visual Basic:

    switch (p.Age)
    {
        case var n when n < 16:
            Console.WriteLine(“Can’t vote yet!”);
            break;
        default:
            Console.WriteLine(“Potential voter!”);
            break;
    }

La cláusula when se puede asociar también a los patrones de tipo. El código que sigue es una modificación del utilizado en el ejemplo de la entrega anterior, en el que ahora se contabilizan las mascotas según su tipo y las personas según su edad. Reconozco que el ejemplo no es el mejor; observe la cantidad de código que se duplica debido al hecho de que únicamente una de las ramas de una sentencia switch se ejecuta.

class MainClass
{
    static void Main(string[] args)
    {
        Process(
            new Employee("Octavio"55"Software Eng."),
            new Person("Diana"21),
            new Pet("Shelly"PetType.DOG11)
        );
    }

    static void Process(params object[] data)
    {
        int people = 0, oldPeople = 0;
        int pets =  0, dogs = 0, cats = 0;
        foreach (var obj in data)
        {
            switch (obj)
            {
                case null:
                    break;

                case Pet pet when pet.Type == PetType.DOG:
                    Console.WriteLine($"{pet.Name} [{pet.Type}]");
                    pets++;
                    dogs++;
                    break;
                case Pet pet when pet.Type == PetType.CAT:
                    Console.WriteLine($"{pet.Name} [{pet.Type}]");
                    pets++;
                    cats++;
                    break;
                case Pet pet:
                    pets++;
                    break;

                case Employee e:
                    Console.WriteLine($"{e.Name} ({e.Position})");
                    people++;
                    if (e.Age > 50)
                        oldPeople++;
                    break;
                case Person p when p.Age > 50:
                    Console.WriteLine(p.Name);
                    people++;
                    oldPeople++;
                    break;
                case Person p:
                    Console.WriteLine(p.Name);
                    people++;
                    break;

                default:
                    Console.WriteLine("** Invalid input!");
                    break;
            }
        }
        Console.WriteLine($"Total {people} people, {oldPeople} of them old.");
        Console.WriteLine($"Total {pets} pets, of them {dogs} dogs and {cats} cats.");
    }
}

La adición de la cláusula when a la sentencia switch es en buena medida ortogonal con la presencia de esta cláusula en los bloques catch de manejo de excepciones (desde C# 6.0) para implementar lo que se conoce como filtrado de excepciones. Para esto sí que he encontrado algunos casos de uso práctico en la vida real; por ejemplo, cuando se necesita discriminar ciertos tipos de errores durante el acceso a una base de datos de SQL Server según su código (vea, por ejemplo, este enlace).


Referencia musical: Llueve mucho en estos días (suceso bastante muy poco común) aquí en el sur de California, así que echo mano de este viejo clásico de Albert Hammond. Que en realidad no trata tanto del clima local ni la lluvia como de lo mal que lo puedes pasar por estos lares si te toca una racha de mala suerte.

Octavio Hernandez

Desarrollador y consultor en tecnologías .NET. Microsoft C# MVP entre 2004 y 2010.

Deja un comentario

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