C# 7 introduced pattern matching with the extension of the switch statement and the is operator offering the const pattern, the type pattern, and the var pattern. With C# 8 an extension of pattern matching is planned, including the property pattern, the recursive pattern, and a new switch – the switch expression.

Pattern Matching with the switch Statement
With C# 7, pattern matching was introduced in C#. The following sample makes use of pattern matching in the switch statement, and type pattern matches. With the first case, also the when clause is used to filter only shapes where the size of the shape has a minimum height. The second and third cases match shapes with a smaller height, but only objects of type Ellipse and Rectangle. For all the other shapes, the default case is chosen:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| static string M1(Shape shape) | |
| { | |
| switch (shape) | |
| { | |
| case Shape s when s.Size.height > 100: | |
| return $"large shape with size {s.Size} at position {s.Position}"; | |
| case Ellipse e: | |
| return $"Ellipse with size {e.Size} at position {e.Position}"; | |
| case Rectangle r: | |
| return $"Rectangle with size {r.Size} at position {r.Position}"; | |
| default: | |
| return "another shape"; | |
| } | |
| } |
The Shape class makes use of tuples and deconstruction. The read-only property Position is a tuple type containing two int values for x and y. The property Size is a tuple containing two int values for height and width. The Shape defines a constructor where the position and size is initialized. With the implementation of the constructor, on the right side a tuple is created containing the position and the size, and this tuple is deconstructed to fill the Position and Size properties.
The Deconstruct method is used to deconstruct two tuples for the size and the position out of the Shape class. This deconstruction will be used later with pattern matching.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public abstract class Shape | |
| { | |
| public (int x, int y) Position { get; } | |
| public (int height, int width) Size { get; } | |
| public Shape((int x, int y) position, (int height, int width) size) | |
| => (Position, Size) = (position, size); | |
| public void Deconstruct(out (int x, int y) position, out (int x, int y) size) | |
| => (position, size) = (Position, Size); | |
| public string Name => GetType().Name; | |
| } |
In the Main method of the application, an array of Shape objects is created, and in turn the foreach statement is invoked. The object is passed to the M1 method shown earlier making use of pattern matching.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| static void Main() | |
| { | |
| var r1 = new Rectangle(position: (200, 200), size: (200, 200)); | |
| var e1 = new Ellipse(position: (80, 1400), size: (80, 140)); | |
| var shapes = new Shape[] | |
| { | |
| r1, | |
| e1, | |
| new Circle((40, 60), 90), | |
| new CombinedShape(r1, e1) | |
| }; | |
| foreach (var shape in shapes) | |
| { | |
| Console.WriteLine(M1(shape)); | |
| } | |
| } |
Install C# 8
At the time of this writing, C# 8 is not yet released. However, you can try it out. At the time of this writing, to try C# 8 patterns, Visual Studio 2017 15.5-15.7 is needed – and the preview of C# Patterns and Ranges. You can easily install it, and uninstall it as described in the linked article.
Be aware that the features shown here might look different in the released product, or also might be removed or delayed to a later version of C#.
Using the switch expression
C# 7 extended the scenarios where you can use expression bodied members. However, as soon as you use the switch statement, the method cannot be implemented using the expression syntax. This changes with the new switch expression.
The switch expression is simplified compared to the switch statement. First, the order of the switch keyword and the variable used is reversed. Instead of writing switch (shape), you write shape switch. The case keyword is not needed with the new syntax. Every case is decided by a pattern, e.g. the type pattern Ellipse e where the variable e is filled in this case. You can also use the when filter as used in the earlier C# 7 pattern matching sample. This syntax is the same as before. The break keyword is also not needed. The implementation of the case follows the lambda operator. After a comma, the next pattern specifies the next case. The new discard pattern with the _ specifies the default case. This new pattern can also be used with the switch statement used previously in case of default.
What if multiple statements are needed in a single case? You can use local functions in such a scenario.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| static string M2(Shape shape) | |
| => shape switch | |
| { | |
| Shape s when s.Size.height > 100 => $"large shape with size {s.Size} at position {s.Position}", | |
| Ellipse e => $"Ellipse with size {e.Size} at position {e.Position}", | |
| Rectangle r => $"Rectangle with size {r.Size} at position {r.Position}", | |
| _ => "another shape" | |
| }; |
Property Pattern, Recursive Pattern
The new switch epression can also be simplified using more new C# 8 pattern matching features. The case matching the Ellipse, now deconstruction is used to fill the pos and size variables.
With the match for the Rectangle, the position is ignored from the deconstruction – using the discard pattern.
The second case is a match for the Shape itself. Because the variable shape is of type Shape, a declaration for the Shape type is not needed. Using curly brackets, the property pattern is used. Here a match only happens if the Size property has a value of (200, 200) (a tuple). The result from the Position property is assigned to the pos variable.
With the match for the CombinedShape class, a recursive pattern is used. The CombinedShape class defines deconstruction to shape1 and shape2. The first shape of this CombinedShape is assigned to the variable shape1. With the second shape, a recursive pattern allows deconstruction of the inner shape – the Position of the second shape is assigned to the pos variable, and the inner size is ignored.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| static string M3(Shape shape) | |
| => shape switch | |
| { | |
| CombinedShape (var shape1, var (pos, _)) => $"combined shape – shape1: {shape1.Name}, pos of shape2: {pos}", | |
| { Size: (200, 200), Position: var pos } => $"shape with size 200×200 at position {pos.x}:{pos.y}", | |
| Ellipse (var pos, var size) => $"Ellipse with size {size} at position {pos}", | |
| Rectangle (_, var size) => $"Rectangle with size {size}", | |
| _ => "another shape" | |
| }; |
Summary
C# 7 introduced pattern matching with the type pattern, the const pattern, and the var pattern. C# 8 extends pattern matching with the discard pattern, the property pattern, and the recursive pattern. Patterns that can simplify code written today.
The new switch expression offers a more modern way for switch/case/break, whereas the case and break keywords are no longer needed.
What do you think about this new C# 8 feature?
Read C# 8 & No Nore NullReferenceExceptions – What about legacy code? for another feature on C# 8.
Get the complete sample from More Samples!
Before C# 8 is released, read about all the cool C# 7 features in the book Professional C# 7 and .NET Core 2.0!
Enjoy programming and learning,
Christian
If you found this information valuable and want to return me a favor, then buy me a coffee.


Examples?
LikeLike
Here is the complete link within the mentioned MoreSamples repository: https://github.com/ProfessionalCSharp/MoreSamples/tree/master/CSharp/CSharp8Patterns
Greetings,
Christian
LikeLike