This is not a new feature, pattern matching in switch statements has been around since C# 7.0. I got a question the other day from a co-worker about how I would do pattern matching when working with a switch. I told him to consider it a mix of a switch and if statements (this way we can avoid nesting both of them). I thought it would be a good idea to make an article showing how it’s done.
In this article, I will teach you how to do pattern matching in switch statements and briefly what the C# compiler produces when processing switch statements. If you are ready – let’s get started.
Video Tutorial
I normally use the switch
statement to select one of many code blocks to be executed. First, let’s have a look at what a normal switch statement looks like.
switch(expression)
{
case x:
// code block
break;
case y:
// code block
break;
default:
// code block
break;
}
How does a C# switch work?
I have sliced the functionality of a switch
statement into four steps, below:
1. The switch
expression is evaluated once
2. The value of the expression is compared with the values of each case
3. If there is a match, the associated block of code is executed
4. The break
and default
keywords will be described later in this article
The example above would evaluate the expression and choose a case depending on a match from one of the matches.
What is break
in a C# switch?
When your C# code reaches the break
keyword, it will break
out of the switch block. When it breaks out, no more execution will be done in terms of case testing inside the switch block. When your code finds a match to its expression, it will take a break
. By using breaks you can save yourself a lot of execution time because it simply ignores the execution of the rest of your code inside the switch block.
What is default
in a C# switch?
The default
keyword in a C# switch is optional and specifies some code to run if your expression doesn’t match any case in your switch block.
How to do pattern matching in switch statements?
C# 7.0 were the version of C# to introduce a new concept allowing us to do pattern matching (inline kind of like if statements). In the example below I have made a switch to tell me if a rectangle is a square because length and width are equal. The switch will take a Shape as a parameter. A shape can be a circle, rectangle, triangle, etc…
public void DefineShape(Shape shape)
{
switch (shape)
{
case Rectangle s when (s.Length == s.Height):
Console.WriteLine($"{s.Length} x {s.Height} is not a rectangle, but a square.");
break;
case Rectangle r:
Console.WriteLine($"{r.Length} x {r.Height} is a rectangle.");
break;
case Circle c:
Console.WriteLine($"Circle with area of {Math.PI * c.Radious * c.Radious}.");
break;
case Triangle t:
Console.WriteLine($"Triangle with area {(t.Height * t.Width)/2}cm2.");
default:
Console.WriteLine("Unknown shape, please try agian.");
break;
case null:
Console.WriteLine("Provided shape is null");
break;
}
}
The first case is including a when
keyword (an if statement). When we add the when keyword to our case, we can add constraints to our cases. As you can see it’s possible to give the switch one rectangle but get two different case matches.
If the shape got equal length and width the first case will give a match and break out of the switch block. If not we will continue to the next rectangle case and show the length and along with a small text in the console. If we switched the ordering of the two cases, the first case would evaluate to a match and break out of the switch block, giving us a wrong result. Please be careful when adding your cases as they can end up matching with the wrong case if you are using the when
keyword.
I also introduced the optional keywords default and null. If we receive a shape that we don’t recognize, we will return a message showing the requester that we don’t know that shape. If the provided shape is null, the last case will be a match.
Testing pattern matching in switch statements
To make sure the switch above works as expected, I have made a small test showing the different outputs.
PatternMatching.DefineShape(new Circle
{
Radius = 6
});
// Output: "Circle with area of 113.097335529233"
PatternMatching.DefineShape(new Rectangle
{
Length = 4,
Width = 4
});
// Output = "4 x 4 is not a rectangle, but a square."
PatternMatching.DefineShape(new Trapeze());
// Output: "Unknown shape, please try agian."
PatternMatching.DefineShape(null);
// Output: "Provided shape is null"
As you can see the switch will do its pattern matching and match the shape on the right case.
Summary
Pattern matching in switch statements has been here for a while (since C# 7.0). It’s a great feature I use to write cleaner code as I don’t have to nest a lot of if statements. When using the pattern matching feature, we have to keep in mind that the order of the case statements is very important.
When you add the default clause in a switch you can do it where you want, because it will always be evaluated last no matter its location in the switch. I hope you learned something new and now are able to use pattern-matching switch statements in your own applications. If you got any questions, please let me know in the comment. Until next time – Happy coding!