DEV Community

Alex Dhaenens
Alex Dhaenens

Posted on

What the hell is pattern matching?

I know, I know, pattern matching is a fancy word right? Well it is actually the name of a C# 7.0 feature that I found out about some time ago and it is damn handy!

Let us start! You know, when you are writing an epic tale of awesome code, you have a class hierarchy where some classes share a common interface. In my, very (for demonstration purposes) simple example, I have an interface IPerson and two classes: Dwarf and Elf which both inherit from the IPerson interface, because, well, both elves and dwarves are persons. The IPerson interface just has an Age property and the both the dwarf and elf have respectively a DwarfishName and an ElfishName.

As we are on are epic coding tale, we arrive at a point where we have an object of type IPerson. And obviously, we want to access some class specific properties. In our case if the IPerson is a Dwarf we want to access the DwarfishName property and in the case it is an Elf, we want to access its ElfishName property. This is how we would do it without pattern matching:

static void PrintPerson(IPerson person)
        {
            Console.WriteLine("*** PERSON ***");
            Console.WriteLine($"Age: {person.Age}");
            if (person is Elf)
            {
                Elf elf = (Elf) person;
                Console.WriteLine($"Name in elfish: {elf.ElfishName}");
            }

            if (person is Dwarf)
            {
                Dwarf dwarf = (Dwarf) person;
                Console.WriteLine($"Name in dwarfs: {dwarf.DwarfishName}");
            }
        }
Enter fullscreen mode Exit fullscreen mode

First we do a check with the is operator, then we do the approriate cast and lastly , we can access the class specific properties. It isn't much code and nor is it complicated.

But you know, you can do the same in C# 7.0 with less but still very readable code. This is done with so called pattern matching:

static void PrintPersonWithPatternMatching(IPerson person)
        {
            Console.WriteLine("*** PERSON ***");
            Console.WriteLine($"Age: {person.Age}");
            if (person is Elf elf)
            {
                Console.WriteLine($"Name in elfish: {elf.ElfishName}");
            }

            if (person is Dwarf dwarf)
            {
                Console.WriteLine($"Name in dwarfs: {dwarf.DwarfishName}");
            }
        }
Enter fullscreen mode Exit fullscreen mode

What you actually do is just add a variable name after the type you are checking against. The is operator still operates the same, but also puts the casted object inside the variable. Nice right?!?

Sources

https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching
Demo project: https://bitbucket.org/aldhaenens/p-d-demo/src/master/

Top comments (7)

Collapse
 
thatblairguy profile image
That Blair Guy • Edited

That's it? From the buzz,I expected something much more complicated.

Are there other uses?

Collapse
 
alexdhaenens profile image
Alex Dhaenens

Yeah it is quite simple, what you also can do is use this in a switch statement:

switch(person){
   case(Elf f):
   break;
}
Collapse
 
saint4eva profile image
saint4eva

person switch {
case Elf elf =>....
case Dwarf dwarf =>...

}

You can even omit the case keyword.

Collapse
 
thatblairguy profile image
That Blair Guy

Very cool. Wish I'd known about that a few weeks ago. So many features to keep track of across so many languages!

Thread Thread
 
alexdhaenens profile image
Alex Dhaenens

Yes indeed, In this blog series I’ll mainly focus on such lesser known features, stay tuned!

Collapse
 
nielselgers profile image
Niels Elgers

Cool post, Alex! Learned something new.

I've never encountered this concept before because I tend to always avoid type checking.

In what situations do you use/prefer type checking over avoiding it using e.g. Visitor pattern, pulling up to a common interface, ... ?

Collapse
 
alexdhaenens profile image
Alex Dhaenens

Well it depends (as usual). I prefer type checking when I only need to get some properties (that are not in the common interface). Or, which was the case when I found this feature, there was too much (legacy) code (that is executed based on the concrete business class) that I could not move to another class or place. In any other case I would indeed prefer the Visitor pattern.
Why do you prefer to use the Visitor pattern?