C# Pattern Matching
Pattern matching tests a value against a shape and picks a result. A switch expression holds the tests as a list of arms.
Property patterns in a switch expression
Each arm tests the Age property of the person. The arms run from the highest band down.
using System;
record Person(string Name, int Age);
class Program
{
static string Describe(Person person)
{
return person switch
{
{ Age: >= 65 } => person.Name + " is a senior",
{ Age: >= 18 } => person.Name + " is an adult",
_ => person.Name + " is a minor",
};
}
static void Main(string[] args)
{
Console.WriteLine(Describe(new Person("Ana", 70)));
Console.WriteLine(Describe(new Person("Hana", 27)));
Console.WriteLine(Describe(new Person("Bo", 9)));
}
}Type patterns with a when guard
The first arm needs an int that passes the guard. Plain type arms catch the rest of each type.
using System;
class Program
{
static string Kind(object value)
{
return value switch
{
int n when n > 10 => "big number",
int => "small number",
string => "text",
_ => "other",
};
}
static void Main(string[] args)
{
Console.WriteLine(Kind(42));
Console.WriteLine(Kind(3));
Console.WriteLine(Kind("hello"));
}
}Relational patterns on a number
An arm can test a number directly with a comparison. The score falls into the first band it reaches.
using System;
class Program
{
static string Grade(int score)
{
return score switch
{
>= 90 => "top",
>= 50 => "pass",
_ => "fail",
};
}
static void Main(string[] args)
{
Console.WriteLine(Grade(95));
Console.WriteLine(Grade(72));
Console.WriteLine(Grade(30));
}
}Example
using System;
record Person(string Name, int Age);
class Program
{
static string Label(object value)
{
return value switch
{
Person p when p.Age >= 18 => p.Name + " (adult)",
Person p => p.Name + " (young)",
int n => "number " + n,
_ => "something else",
};
}
static void Main(string[] args)
{
Console.WriteLine(Label(new Person("Hana", 27)));
Console.WriteLine(Label(new Person("Bo", 9)));
Console.WriteLine(Label(7));
}
}Key points
- A switch expression tries its arms from top to bottom.
- The first arm that matches gives the result.
- A property pattern tests properties inside braces, such as { Age: >= 18 }.
- A type pattern matches when the value has the named type.
- A when guard adds an extra condition to an arm.
- The discard arm _ matches anything and usually comes last.
In this example, the Label method switches over an object of any type. The first arm matches a Person and binds it to p, and its guard checks the age. A younger Person falls to the second arm. An int matches the third arm and prints with its value.
Note
Arm order matters, because a wide arm placed early hides the arms below it.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
When does the arm `{ Age: >= 18 } => "adult"` match a Person?