Page 23 - MSDN Magazine, May 2019
P. 23

Distinguishing between the type of fruit and an attribute of the fruit is exactly what pattern matching is about. Developers have different ways of expressing themselves when identifying this.
Traditionally, I could check all of this using a simple condition. But what if I need to explicitly use the apple? I’d end up in a situ- ation where I must first validate the type, attribute and then cast to an apple. This code quickly ends up a bit messy and, frankly, it’s error prone.
For its part, C# 7.0 introduced a lightweight version of pattern matching that can be helpful, though it lacks many of the nice features present in other languages.
Here’s an example where I validate the specific type of fruit to be an apple. I apply an attribute constraint, and then to use it I have to cast it, like so:
if(fruit.GetType() == typeof(Apple) && fruit.Color == Color.Green) {
var apple = fruit as Apple;
}
Another approach I could take is to use the is keyword, which gives me a little bit more flexibility. As opposed to the previous example, the is keyword will also match on derived apples:
if(fruit is Apple) {
MakeApplePieFrom(fruit as Apple); }
In this case, if the fruit is a derived type of apple, I’ll be able to make an apple pie out of it. Whereas in the earlier example, it would have to be a very specific type of apple.
Fortunately, there’s a better way. As I mentioned, languages like Swift and Kotlin allow you to use pattern matching. For its part, C# 7.0 introduced a lightweight version of pattern matching that can be helpful, though it lacks many of the nice features present in other languages. You can refactor the previous expression into the C# 7.0 code that follows, which allows you to use a switch to match your different patterns. It isn’t perfect, but it does improve on what was previously available. Here’s the code:
switch(fruit) {
case Apple apple: MakeApplePieFrom(apple); break;
default: break;
}
A few things here are interesting. First, notice that I don’t have a single type cast anywhere in this code, and also that I can use the apple just matched on in the case context. Just as with the is keyword, this will match on derived apples, as well. msdnmagazine.com
This C# 7.0 code also reads better, and is much easier to have con- versations around, than similar code in C# 6.0. The code is just saying, “Based on the fact that fruit is an apple, I want to use this apple.” Each case can match on a type that shares similar traits, meaning they inherit from the same class, for instance, or implement the same interface. In this case, an apple, pear and banana are all fruits.
What’s missing is a way to filter out the green apples. Have you seen exception filters? That’s a feature introduced in C# 6.0 that allows you to catch certain exceptions only when a certain condi- tion is met. This feature introduced the when keyword, which is applicable in pattern matching, as well. I can match the apple using pattern matching, and only enter the case when the condition is met. Figure 1 shows this.
As Figure 1 illustrates, the order matters. I first look for an apple with the color green, because this characteristic is the most important to me. If there’s another color, let’s say brown, this would indicate that my apple has gone bad and I want to throw it out. As for all other apples, I don’t want them in the pie, so I’ll just eat them. The final apple pattern is a “catch all” for all apples that have neither a green nor a brown color.
You’ll also see that if I get an orange, I’ll just peel the skin off. I’m not limited to handling one particular type; as long as the types all inherit from fruit, we’re good to go.
Everything else works like the normal switch that you’ve been using since C# 1.0. This example was written entirely in C# 7.0, so the question is, is there room for improvement? I would say so. The code is still a bit on the expressive side, and it could be made more readable by improving the way patterns are expressed. Also, it would help to have other ways to express constraints against what my data “looks like.” Let’s now jump into C# 8.0 and look at the changes that have been introduced to make our lives easier.
The Evolution of Pattern Matching in C# 8.0
The latest version of C#, currently in preview, introduces some import- ant pattern-matching improvements. To try C# 8.0, you’ll have to use Visual Studio 2019 Preview, or enable the preview language features in Visual Studio 2019. The general availability of C# 8.0 is later this year, expected at the same time that .NET Core 3.0 ships. How can
Figure 1 Applying a Filter Using the When Keyword
Fruit fruit = new Apple { Color = Color.Green }; switch (fruit)
{
case Apple apple when apple.Color == Color.Green: MakeApplePieFrom(apple);
break;
case Apple apple when apple.Color == Color.Brown: ThrowAway(apple);
break;
case Apple apple: Eat(apple); break;
case Orange orange: orange.Peel(); break;
}
May 2019 17


































































































   21   22   23   24   25