C# 8.0: Mejoras en el emparejamiento de patrones (y II)

“Button up your overcoat
When the wind is free
Take good care of yourself
You belong to me!”
Frank Sinatra, “Pick Yourself Up”

Ante todo, quiero desearle a todos mis lectores que el pérfido COVID-19 pase de largo sin tocarles, y exhortarlos a que se cuiden y cuiden a los suyos: ¡hay mucho futuro por delante después que hayamos vencido al odioso bichito!

De la entrada anterior, donde hablamos sobre las mejoras introducidas por la versión 8.0 de C# en relación con el emparejamiento de patrones (pattern matching), nos quedó pendiente la presentación de los patrones posicionales, omisión que intentaremos subsanar ahora.

Los patrones posicionales permiten utilizar el mecanismo de deconstrucción introducido en C# 7.0 (del que hablamos hace algún tiempo aquí) para expresar patrones recursivos que combinen un patrón de emparejamiento por el tipo de datos con uno o más patrones internos en los que se «casen» uno a uno los resultados de la deconstrucción del objeto sujeto a emparejamiento. En C# 7.x, la deconstrucción no se puede utilizar en escenarios de emparejamiento de patrones.

Continuando con el ejemplo de la entrega anterior, supongamos que la clase Address incluye el siguiente mecanismo de deconstrucción:

public static class AddressExtensions
{
    public static void Deconstruct(this Address address, 
        out string address1, out string address2, out string city, 
        out string state, out string zipCode, out string country)
    {
        address1 = address.StreetAddress;
        address2 = address.StreetAddress2;
        city = address.City;
        state = address.State;
        zipCode = address.ZipCode;
        country = address.Country;
    }
}

Entonces el método para determinar si una cierta dirección pertenece al downtown de la ciudad de Los Ángeles, que la vez anterior escribimos así:

public static bool IsDowntownLA(this Address address)
{
    return (address.City, address.ZipCode) is ("Los Angeles", "90012");
}

Podríamos también haberlo escrito así:

public static bool IsDowntownLA_v2(this Address address)
{
    return address is Address(_, _, "Los Angeles", "CA", "90012", _);
}

Con los patrones posicionales y recursivos, Microsoft resuelve muchos de los problemas de «superficialidad» en el emparejamiento de patrones en C# 7.0 de los que me quejaba en el artículo antes mencionado. Si, por ejemplo, la propiedad State de Address fuera un objeto compuesto en lugar de una simple cadena de caracteres, se podría especificar un objeto-patrón en la posición correspondiente, y éste sería emparejado recursivamente. ¡Esto ya se va pareciendo bastante a la unificación (unification) de Prolog (aunque, claro, en una sola dirección ;-))!

Por supuesto, el lector coincidirá conmigo en que la versión original de IsDowntownLA es mejor que la nueva. Aquélla es más legible, y ésta tiene una dependencia directa del orden (o posición) de los parámetros de la deconstrucción, cosa que puede darnos algún que otro dolor de cabeza de mantenimiento. Pero seguramente pueden encontrarse escenarios en los que estos riesgos sean mínimos. Por ejemplo, la documentación de Microsoft utiliza en sus fragmentos de código la clase Point, donde es obvio que los parámetros debe ser x, y, z (en ese orden).


Referencia musical: Tanto Frank Sinatra como Nat King Cole se oían muy frecuentemente en mi casa cuando era niño, y aún no he podido librarme totalmente de su embrujo.

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 *