C# 8.0: Enhancements in pattern matching (II)

You can find the original (Spanish) version of this post here.

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

In the very first place, I would like to wish all my readers that the perfidious COVID-19 leaves you unscathed, and to encourage you to take care of yourselves and your loved ones – there is so much future ahead of us once we have beaten the obnoxious bug!

In the previous post, where we talked about the enhancements added to the 8.0 version of C# in connection with pattern matching, we left pending a presentation of the new positional patterns; we will try to address that omission here.

Positional patterns allow us to leverage the deconstruction mechanism introduced in C# 7.0 (we talked about it quite some time ago here) to create recursive patterns that combine a type pattern with one or more internal patterns so that the results of the deconstruction of the object subject to matching are recursively matched one by one against those internal patterns. Notice that in C# 7.x, deconstruction could not be used in pattern matching scenarios.

Continuing with the example of the previous post, let’s assume that the Address class includes the following deconstruction mechanism:

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;
    }
}

Then the method to determine whether a certain address belongs to the Los Angeles downtown, which last time we implemented like this (using a tuple pattern):

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

Could now be also written like this:

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

With the positional patterns and their support for recursion, Microsoft has solved most of the «shallowness» problems in the C# 7.0 pattern matching of which I had complained in the aforementioned post. If, for instance, the City property of Address were an object (with its corresponding deconstructor defined) instead of a simple character string, we would be able to supply a type pattern in the corresponding position, and it would be recursively matched:

public class City
{
    public string Name { getprivate set; }
    public int Population { getprivate set; }

    public City(string name, int population)
    {
        Name = name;
        Population = population;
    }
}
public static class CityExtensions
{
    public static void Deconstruct(this City city,
        out string name, out int population)
    {
        name = city.Name;
        population = city.Population;
    }

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

This already looks pretty similar to Prolog’s unification! (although, of course, just in one direction ;-)).

Surely the reader will agree with me in that the original version of IsDowntownLA looks better than the newer ones. The former is more readable, and does not have such as strong dependence on the order (position) of the deconstruction parameters as the other two versions do, which could probably be the source of some future maintenance headaches. But surely you will find scenarios where the associated risks are minimal. For instance, the Microsoft documentation uses in its code fragments the Point class, for which it’s obvious that the deconstruction parameters should be x, y, z (in that order).


Cultural reference: Both Frank Sinatra and Nat King Cole were frequently played in my house when I was a kid, and I’ve never been able to fully break their spell.

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 *