Another concept from functional programming languages making its way to C# and VB is what’s known as pattern matching. At first glance pattern matching looks like a switch/select block, but it is much more powerful.
Note: Since the VB version of the specification isn’t available yet, many of these examples are from C# pattern matching specification.
The is or Matches operator
At the core of .NET’s pattern matching support is the “is/Matches” operator. This rather unusual operator breaks down a class into its constituent parts. Here is an example based on the Cartesian record class from Tuesday’s report.
public static bool operator is(Cartesian c, out double x, out double y)
x = c.X;
y = c.Y;
return true;
}
This operator is not just limited to the owning type. Here is an example of defining the operator in a way that allows it to decompose a Cartesian object as if it were a Polar object.
public static class Polar {
public static bool operator is( Cartesian c, out double R, out double Theta)
{
R = Math.Sqrt(c.X*c.X + c.Y*c.Y);
Theta = Math.Atan2(c.Y, c.X);
return c.X != 0 || c.Y != 0;
}
}
var c = Cartesian(3, 4);
if (c is Polar(var R, *))
Console.WriteLine(R);
Type Patterns
The simplest pattern is the Type pattern, which is essentially a try-cast with assignment. Here is an example:
if (expr is Type v)
{ // code using v }
Recursive Pattern
Most patterns are going to be recursive. That is to say, they are made up of other, often simpler, patterns. Consider this example:
var a = new Location(1, 2, 3); //x=1, y=2, z=3
if (a is Location(1, var y, *))
This is a recursive pattern consisting of a constant pattern, and var pattern, and a wildcard pattern.
Constant Pattern
This is when a match is made between a property and a constant value. Constant patterns use object.Equals(left, right) to see if there is a match.
Var Pattern
The var pattern is always considered a match. The associated variable is populated with the value coming from the is operator. The type of this variable is the statically defined type of the expression.
Wildcard Pattern
The wildcard pattern is essentially the var pattern, except you don’t care about the result.
Under the hood
Continuing with our location example, the steps the compiler takes will resemble this:
- Create variables $x, $y, and $z
- Call Location.is(a, out $x, out $y, out $z) and verify it returns true
- Constant Pattern: Check that object.Equals($x, 1)
- Var Pattern: Set y = $y
- Wildcard Pattern: Ignore $z
Switch/Select Case Blocks
Switch blocks will be extended to use pattern matching. Essentially this means you can write statements such as:
case null:
case String s
case Location(1, var y, *):
Limitations
Under the current draft specification, there is no support for range checks. This means you cannot write patterns such as “a is Location( > 0, 1 to 5, <= 10)”. Nor is there support for matching elements in a list or enumeration.
Correction: This report erroneously stated that this feature would be part of C# 6 and VB 12.