Menú de navegaciónMenú
Categorías

La mejor forma de Aprender Programación online y en español www.campusmvp.es

?id=0636c06d-aca1-43c5-91c0-ab34d02d8e1b

Lenguaje C#: Coincidencia de modelos - Parte 1: Fundamentos

Imagen ornamental

Si has aprendido el lenguaje C# hace ya unos años, seguro que las limitaciones que han tenido tradicionalmente los switch te han exasperado más de una vez, ya que básicamente te dejaban hacer una comparación entre una variable y un valor, y poco más.

Si es así, no te preocupes: en este artículo vas a descubrir todo un nuevo mundo de posibilidades que tienes en la actualidad para la toma de decisiones gracias a la coincidencia de modelos en C#.

La coincidencia de modelos o pattern matching es un patrón que nos permite ejecutar un determinado código cuando el dato que recibimos coincida con un modelo determinado. Este patrón de decisión apareció con la versión 7 de C#, pero será en la versión 8 (en septiembre de 2019) cuando se amplíen en serio sus capacidades para crear la potente herramienta que es en la actualidad. Y en C# 9 también se añadieron nuevas posibilidades a esta característica, por lo que descubrirás un nuevo mundo de opciones a la hora de utilizarlos.

Las diferentes opciones que tenemos a la hora de usar coincidencia de modelos son:

Con C# 7:

  • Uso en el if
  • Instrucción switch

Con C# 8:

  • Uso de expresiones con switch (ojo: no es el switch tradicional que conoces de toda la vida en C#. Enseguida lo verás...)
  • Aplicado en propiedades
  • En tuplas
  • Empleo posicional

Y, de igual forma, con la versión 9 del lenguaje se incrementaron en 2 patrones más que están basados también en el empleo de la palabra reservada switch.

  • Patrones simples
  • Patrones relacionales
  • Patrones lógicos

En este primer artículo vamos a ver la coincidencia de modelos básica, tanto en condicionales como en switch.

Coincidencia de modelos en el if

Cuando trabajas con interfaces o con diferentes tipos de datos puedes usar un switch para decidir que se ejecute un determinado código u otro en función de que el tipo de dato coincida con una determinada interfaz o un determinado tipo de dato. Es algo muy común.

De la manera tradicional lo conseguimos comprobando en primer lugar el tipo para, posteriormente, realizar un cast. Sería algo así:

private static void MostrarPorConsola(object objeto)
{
    if (objeto is Profesor)
    {
        Profesor profesor = objeto as Profesor;
        Console.WriteLine("Profesor: " + profesor.Nombre + " " + profesor.Apellidos);
    }
    else if (objeto is Alumno)
    {
        Alumno alumno = objeto as Alumno;
        Console.WriteLine("Alumno: " + alumno.Nombre + " " + alumno.Apellidos);
    }
    else
        Console.WriteLine("Función ejecutada");
}

En este caso, lo que se hace es comprobar si el objeto es una instancia de la clase Profesor o de la clase Alumno. Si es una de las dos, se ejecuta el código correspondiente. Si no es ninguna de las dos, se ejecuta el código que se pasa como parámetro.

Con la coincidencia de modelos lo que se busca es simplificar el código y reducir la posibilidad de error.

Con este patrón, lo que vamos a definir es en el propio if la comprobación de tipo exactamente igual que en el ejemplo anterior, pero además incluiremos una variable en la que realizará el volcado en el caso de coincidir el modelo, así:

private static void MostrarPorConsola(object objeto)
{
    if (objeto is Profesor profesor)
        Console.WriteLine("Profesor: " + profesor.Nombre + " " + profesor.Apellidos);
    else if (objeto is Alumno alumno)
        Console.WriteLine("Alumno: " + alumno.Nombre + " " + alumno.Apellidos);
    else
        Console.WriteLine("Función ejecutada");
}

Si observamos el nuevo código, se puede apreciar que es más breve al eliminar la necesidad de realizar el cast nosotros mismos. Además se elimina el riesgo de asignaciones no deseadas, puesto que si no coincide el modelo, no se puede llegar a producir.

Coincidencia de modelos en el switch

La aparición de este patrón en la instrucción switch altera el comportamiento de forma que, lo que incluiremos en las cláusulas case, no será un valor fijo o constante como se hace tradicionalmente, sino que podremos incluir también el tipo de dato con el que se tiene que corresponder la variable que le pasamos al switch.

Esto proporciona una gran potencia adicional. Para ilustrarlo, vamos a modificar el ejemplo anterior de modo que tratemos de forma diferenciada profesores, alumnos y conserjes a través de sus correspondientes clases:

private static void MostrarPorConsola(object objeto)
{
    switch (objeto)
    {
        case Profesor profesor:
            Console.WriteLine("Profesor: " + profesor.Nombre + " " + profesor.Apellidos);
            break;
        case Alumno alumno:
            Console.WriteLine("Alumno: " + alumno.Nombre + " " + alumno.Apellidos);
            break;
        case Conserje conserje:
            Console.WriteLine("Conserje: " + conserje.Nombre + " " + conserje.Apellidos);
            break;
        default:
            Console.WriteLine("Función ejecutada");
            break;
}

Lo que ocurre en este ejemplo es que, al pasar un dato al switch, comprueba los diferentes case en el orden que los hemos puesto. En el momento en que el tipo de objeto se corresponda con el especificado en el case, de igual forma que se haría con el operador is, lo va a asignar a la variable que se encuentra en la derecha del tipo coincidente. Para finalizar ejecutará el código que se encuentra en dicho case.

Esto proporciona una manera más clara y concisa de realizar este tipo de comprobaciones.

Filtrado en el switch: Cláusula when

Partiendo del código anterior, podremos dar un paso más añadiendo un filtrado al tipo especificado en el case mediante el uso de la cláusula when.

De este modo podremos ejecutar un código diferenciado en función de los datos contenidos dentro del objeto en cuestión.

Hay que tener presente, que la cláusula when contendrá un predicado, es decir, una expresión que devolverá un valor booleano que determinará si se cumple o no la condición.

Repetiremos el código anterior, pero ahora los alumnos y profesores cuyo nombre empiece por "A" los procesaremos de forma diferenciada:

private static void MostrarPorConsola(object objeto)
{
    switch (objeto)
    {
        case Profesor profesor when profesor.Nombre.StartsWith("A"):
            Console.WriteLine("Profesor que empieza por A: " + profesor.Nombre + " " + profesor.Apellidos);
            break;
        case Alumno alumno when alumno.Nombre.StartsWith("A"):
            Console.WriteLine("Alumno que empieza por A: " + alumno.Nombre + " " + alumno.Apellidos);
            break;
        case Profesor profesor:
            Console.WriteLine("Profesor: " + profesor.Nombre + " " + profesor.Apellidos);
            break;
        case Alumno alumno:
            Console.WriteLine("Alumno: " + alumno.Nombre + " " + alumno.Apellidos);
            break;
        case Conserje conserje:
            Console.WriteLine("Conserje: " + conserje.Nombre + " " + conserje.Apellidos);
            break;
        default:
            Console.WriteLine("Función ejecutada");
            break;
}

MUCHO CUIDADO: es muy importante ordenar correctamente los case pues si hubiésemos colocado antes las opciones sin when, nunca llegaría a entrar en las opciones con when puesto que se cumple la condición antes.

Aunque ya hemos mejorado algo respecto a lo que había antes de C# 7, con esto solo hemos arañado la superficie. En la próxima entrega verás cómo puedes sacarle partido a todas las modalidades adicionales y avanzadas de coincidencia de patrones para crear código con switch realmente potente pero además fácil de leer y mantener. Hasta pronto...

Rubén Rubio Rubén lleva muchos años trabajando como desarrollador de software con diversas tecnologías y certificado por Microsoft desde el año 2003 en desarrollo con .NET. Ha trabajado como analista, desarrollador y responsable de TI en empresas de diferentes sectores. Actualmente trabaja como consultor y desarrollador independiente, ofreciendo sus servicios a empresas e instituciones, siendo también autor y docente en campusMVP. Ver todos los posts de Rubén Rubio
Archivado en: Lenguajes y plataformas

¿Te ha gustado este post?
Pues espera a ver nuestro boletín mensual...

Suscríbete a la newsletter

La mejor formación online para desarrolladores como tú

Comentarios (1) -

Fernando PUyuelo
Fernando PUyuelo

Interesante y muy claros los ejemplos.

Responder

Agregar comentario

Los datos anteriores se utilizarán exclusivamente para permitirte hacer el comentario y, si lo seleccionas, notificarte de nuevos comentarios en este artículo, pero no se procesarán ni se utilizarán para ningún otro propósito. Lee nuestra política de privacidad.