Pattern matching is another idea common to functional languages that has gradually crept into C#. Pattern matching refers to extracting information from structured data by matching the shape of that data.
We’ve already seen the pattern-matching is operator in our discussion of casting. This allows us to extract the cast version of a variable and assign it to a new one:
if(oldVariable is SpecificType newVariable)
{
// within this block newVariable is (SpecificType)oldVariable
}
The switch
statement is also an example of pattern matching. The traditional version only matched constant values, i.e.:
switch(choice)
{
case "1":
// Do something
break;
case "2":
// Do something else
break;
case "3":
// Do a third thing
break;
default:
// Do a default action
break;
}
However, in C# version 7.0, this has been expanded to also match patterns. For example, given a Square
, Circle
, and Rectangle
class that all extend a Shape
class, we can write a method to find the area using a switch:
public static double ComputeCircumference(Shape shape)
{
switch(shape)
{
case Square s:
return 4 * s.Side;
case Circle c:
return c.Radius * 2 * Math.PI;
case Rectangle r:
return 2 * r.Length + 2 * r.Height;
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape)
);
}
}
Note that here we match the type of the shape
and cast it to that type making it available in the provided variable, i.e. case Square s:
matches if shape
can be cast to a Square
, and s
is the result of that cast operation.
This is further expanded upon with the use of when
clauses, i.e. we could add a special case for a circle or square with a circumference of 0:
public static double ComputeCircumference(Shape shape)
{
switch(shape)
{
case Square s when s.Side == 0:
case Circle c when c.Radius == 0:
return 0;
case Square s:
return 4 * s.Side;
case Circle c:
return c.Radius * 2 * Math.PI;
case Rectangle r:
return 2 * r.Length + 2 * r.Height;
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape)
);
}
}
The when
applies conditions to the match that only allow a match when the corresponding condition is true.
C# 8.0, which is currently in preview, has expanded greatly upon pattern matching, adding exciting new features, such as the switch expression, tuples, and deconstruction operator.