๐ŸŽ“ A1Learner
๐Ÿ”
0 of 38 lessons completed

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?