Get in touch

Get in touch with Binary

Binary Studio website uses cookies to enhance your browsing experience. By continuing to use our site, you agree to our Privacy Policy and use of cookies.

Learn more more arrow
Kirill Miroshnichenko .NET Developer 20.07.2017

Pattern Matching in C# and things you should know about it

Every new version of C# language specification brings us something tasty to try, something that makes the developer’s life easier and the code more clean and understandable.
In the last few versions, the Microsoft team brings a breath of fresh air into the ability to build conditional logic. In this article, we will go through the new syntax in-depth and see on the real examples of how to use pattern matching and how it actually works.

With C# 7.0 we get a new conception of patterns. We can describe them as special language elements that help check values for specific characteristics and extract them. Using C# 7.0 you can use already known language constructions (switch-case and is) in a slightly different way. The patterns themselves can have the form of constants and types. Additionally, when type patterns are used, the checked value can be immediately saved into a variable.

Let’s demonstrate all the new stuff with real examples. In the previous version we could write something similar to the next example:

Here we check passed obj value against type (type pattern). With the new syntax the same can be done much easier:

We can even use a fancy var keyword:

Examples above are called Type Pattern and Var Pattern respectively. In addition to casting, you can also compare a variable with a value:

But wait, there’s more! We can use this ability even when we don’t know the exact object type:

This type of pattern matching is called Const Pattern.

New possibilities naturally combine together:

Just look at this neat code and imagine what you would have to write without the new syntax.
Ok. Now it should be clear. But the interesting thing is what happens inside. Let’s compile and decompile it to understand how it actually looks without the syntax sugar:

Everything is quite simple, but it’s ugly…

In the example above, in the method DemoCat, we used a reference type. But what happens if we do pattern matching against a value type?

A value type cannot be used with the operator ‘as’ and cannot be translated the same way in the background as it was with the reference Cat object. But anyway, the new syntax somehow allows us to do the check, and it looks the same. And what actually happens is the following:

The compiler translates the matching expression through the nullable type.

Let’s move further. We can see more interesting examples when pattern matching is used in the switch-case construction. In the old version, only constants were allowed near the case and the switch itself supported only enums, strings and base types like int, bool, char, etc.

The following example demonstrates different kinds of pattern matching in the switch-case construction and its new features:

And traditionally, let’s look at the decompiled version:

Honestly, I don’t even want to try to understand what is happening there…

With C# 8.0 pattern matching for switch-case construction goes even further. It brings three more features to make your code even more elegant: switch expression, property patterns and tuple patterns.

Let’s start with switch expression. Usually, we want to separate responsibilities in our code. So we can rewrite the previous example using next two methods: first, it gets the string by condition and then it prints the string.

That’s amazing! Here I don’t use any boilerplate and every line contains only useful code. It allows you to write more declarative code instead of imperative and also omit all type checking and null reference exceptions.

So far so good. Now we look at even more powerful comparisons with a property pattern. Let's say we have a set of people, and we want to call them differently based on their first name and last name:

You can see that we can track every property within an object. You can go deeper and even track inner objects without any worry about null references - if the compiler doesn’t find a correct case, it just goes to default one.

The last thing I want to mention is a tuple pattern. Using this feature you can easily construct and deconstruct tuples right in the switch expression.

As you can see, pattern matching and the new syntax related to it help simplify life very much and make the code much cleaner. There are rumors that all this stuff will be even more extended in the next language versions. And now, try new stuff in your projects and may the force be with you!