A quick study of the “C# patterns”

Let’s see how to use handy syntactic sugar to run checks and matches on our variables!

This article is also available on Medium.

C# is just like any other programming language: it’s evolved a lot over the years, and its creators have gradually tried to add in more and more features. It’s now a powerful, diverse and yet (in my opinion) pretty controllable thing, which makes it a really cool language to work with!

In particular, I’m really keen on the various tools C# has of making your code both readable and robust. Be it with the strongly-typed construct that can be relaxed thanks to implicit typing but still run type checks in your IDE, the easy-to-write Linq queries to quickly extract and transform data, the interfaces and classes from the OOP mindset or even the built-in events, the language is now full of amazing features.

But, to me, C# is also great because it has clever syntactic sugars and other shorthands for various tasks. So, today, let’s discuss one of these nice “alternatives”: the patterns.

Patterns & pattern matching

What is a pattern?

First things first, we need to understand what we’re talking about exactly. The word “pattern” is somewhat a generic one; in itself, it can be defined as (see the Merriam-Webster online dictionary):

a form or model proposed for imitation

or:

something designed or used as a model for making things

Ok – basically, it’s about writing something on your blackboard for the rest of the class to copy. Therefore, in truth, we could say that any specific algorithm is sort of a “code pattern”. Similarly, there are well-known “patterns” for storing and organising data. And there are process techniques that we can assimilate to “production patterns”.

But that’s not what I want to talk about here! 😉

In C#, there is a technique called: pattern matching. It is used to test if a given expression matches a certain set of criteria, if it has certain properties. The “pattern” we’re going to talk about are thus about a code expression having the right shape, corresponding to an expected form.

The basics of pattern matching

Pattern matching relies on two important keywords: is and switch.

An is expression” allows you to check if a variable is of a given type, and conditionally auto-declare a new “friend” variable with this specific type. Typically, this is super-useful when you have some class inheritance, and you want to know exactly what child class your variable is:

A switch expression”, on the other hand, is a way of running some logic based on the result of the match, like this:

Note: be careful – we use a switch expression here, not a switch statement! In other words, the keyword switch doesn’t start a new code block in this case, with various case results: it’s directly part of a computation that returns a result 😉

With just these two words, you can already do a lot of neat C# tricks! Let’s see some basic and not-so-basic examples…

Some simple examples

Performing null checks

A very common use case for the “is statement” is to check whether a (nullable) variable is currently null or not. I discussed this in my last C# episode on “weakly-typed” C#: you can take advantage of the is keyword with a simple if-check to avoid trying impossible operations and keep your code sain:

Of course, you might want to actually get the value of your nullable variable – this can be done instantaneously in the “is statement”, just by adding a new variable name at the end. The program will automatically assign the result of the “conversion” to this new variable, if the variable passes the null check 🙂

Checking against interface types

If you’ve ever played around with interfaces and tried to build some of your object’s behaviours with them, you might have discovered that you can’t test if an object has an interface thanks to an equality check, like you’d do for a class.

If you want to know if your variable has a given interface, then you have to make use of the “is statement”; and then you can again retrieve the newly “converted” version of your variable and work with while being absolutely sure that it implements your interface:

Comparing to enums or constants

Using enums and static lists to hold some constants about your project is a tried and tested technique: it insures you don’t accidentally mistype something, and that you stick the list of intended values.

But it can also quickly lead you to write this sort of code:

While not bad per se, it’s a bit straining for the eyes and not as readable as it could be. Of course, you can use the switch statement to simplify things a bit…

But a switch expression goes even further and completely removes all intermediary (unnecessary) keywords and braces!

Each case check is called a “branch” and returns the matching value.

This obviously only works when you directly return your value: if you have to do some computation before having the right result for a given case, then a switch statement might be better suited. But in most cases, for simple discrete values, this pattern matching can be really handy and easy-to-read

And guess what? It also works for conditions! So, you can even use switch expressions for this:

Pretty cool, right? 🙂

Using more complex data

So far, the only examples of a switch expressions we’ve seen had just one input to match against the various branches. But what if you need to check for two values at the same type? Or if you’re working with a class or a struct instance, and you want to access an inner property?

Don’t worry: the switch expression has you covered!

Handling multiple inputs in a switch expression

Let’s say we continue our Ship example but, in addition to the status, we also look at whether there is a human or an AI pilot to know if the ship can fly:

This works, but it’s not very nice to read. Why do we have to use two switch expressions? Instead, we can actually merge everything into one, with two inputs:

Accessing instance properties

If you want, you can also access the properties of an instance from outside and have the switch expression be in your main function:

Discarded values, and the null case

In my previous examples, whenever I wanted to handle the “default” case, I used the _ character. This symbol is called the discard pattern, and it’s a way of telling the program of treating any value not already matched (including null) in this branch of the expression.

But what if you don’t want to include the null case in there?

Then you can use the {} “empty braces” to match any non-null value that hasn’t been matched already:

Conclusion

Pattern matching is a really powerful feature of C#, because it helps make the code more readable, but also keeps all the nice type checks and IDE auto-completion available!

I hope you liked this article — feel free to leave a comment and tell me if you have other ideas for C# posts… and as usual, thanks a lot for reading 🙂

Leave a Reply

Your email address will not be published.