C# 8.0: Mejoras en el emparejamiento de patrones

Hace un par de años, en un artículo publicado en los tiempos de C# 7.x, presentamos los conceptos fundamentales en relación con el emparejamiento de patrones (pattern matching), característica que recién entonces se incorporaba a C# luego de su probado éxito en diferentes lenguajes de programación funcional y lógica (aquí no puedo evitar pensar en Prolog y en quien me lo enseñó, mi querido maestro Dr. Luciano García Garrido, que aún sigue formando profesionales en la Universidad de la Habana). La versión 8.0 de C# ha añadido algunas mejoras con relación a lo que en aquel momento se presentaba como gran novedad; sobre esas mejoras trata precisamente este artículo.

Como bien puede leerse en la página oficial de Microsoft relacionada con las novedades de C# 8.0, el emparejamiento de patrones nos da la posibilidad de expresar funcionalidades dependientes de la forma de los datos; como tal, se trata de un caso particular de programación dirigida por los datos (data-driven programming). La versión 7.0 de C# añadió sintaxis para expresar tres tipos de patrones: los patrones constantes, los patrones de tipo y los patrones var. En un siguiente paso de refinamiento, C# 8.0 ha expandido su vocabulario con nuevos tipos de patrones; además, los patrones, que antes podían utilizarse en dos escenarios, las expresiones is y las sentencias switch, ahora también pueden utilizarse en un tercer contexto: las expresiones switch, de las que ya hablamos aquí. En mi modesta opinión, la referida página de Microsoft no hace un buen trabajo al separar los patrones en sí de los contextos en que pueden utilizarse, cosa que podría llevar a un principiante a confundir los frijoles con la cazuela en que éstos se cuecen ;-). Además, en todos los ejemplos el artículo utiliza expresiones switch; razón por la cual presentaré aquí los nuevos patrones utilizando las otras construcciones.

Los nuevos patrones disponibles en C# 8.0 son los siguientes:

  • Patrones de propiedad: Ahora es posible emparejar una expresión con un patrón usando una propiedad de la expresión. Por ejemplo, si se tiene una clase Address para representar direcciones de correo postal tradicionales, se podría crear el siguiente método para determinar si una dirección corresponde a uno de los estados de la costa oeste de los Estados Unidos:
public static bool IsWestCoast(this Address address)
{
    switch (address)
    {
        case { State: "CA" }: return true;
        case { State: "OR" }: return true;
        case { State: "WA" }: return true;
        default:              return false; 
    }
}
  • Patrones de tupla: Ahora es posible también emparejar una tupla, miembro a miembro, con un patrón de tupla que tenga la misma cantidad de elementos. Este tipo de patrón es útil cuando un algoritmo necesita «casar» varias entradas simultáneamente. Por ejemplo, el siguiente método utiliza una expresión is para determinar si una cierta dirección pertenece al downtown de la ciudad de Los Ángeles:
public static bool IsDowntownLA(this Address address)
{
    return (address.City, address.ZipCode) is ("Los Angeles", "90012");
}

Aunque la documentación oficial a la que antes hacíamos referencia los presenta de manera separada, los patrones de tupla podrían considerarse como un caso particular de los patrones posicionales que se mencionan a continuación.

  • Patrones posicionales: Dejaremos la presentación de los patrones posicionales para la próxima entrega, dado que ésta ya se va haciendo demasiado larga.
  • Por último, vale la pena mencionar que en C# 8.0 los patrones pueden combinarse de manera recursiva. Según la página de Microsoft, «un patrón recursivo es simplemente una expresión-patrón aplicada al resultado producido por otra expresión-patrón». Por ejemplo, suponga que tuviéramos las clases ResidentialAddress y CommercialAddress, derivadas de Address, y quisiéramos definir un método IsCaliforniaBusiness(Address address) para calcular si una dirección corresponde a un negocio o local comercial localizado en California. La versión que se muestra a continuación satisface los requerimientos. En ella primeramente se hace un emparejamiento por el tipo de datos (disponible desde C# 7.0), para luego aplicar un emparejamiento por la propiedad State.
public static bool IsCaliforniaBusiness(this Address address)
{
    return address is CommercialAddress { State: "CA" };
}

15/03/2020: Puede leer la continuación aquí.

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 *