Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Pattern Matching Mastery

โญโญ intermediateโณ 17 min read๐Ÿ“ Lesson 88 of 265

Type patterns, property patterns, relational and logical patterns, switch expressions, tuples, and deconstruction.

From if-chains to patterns

Pattern matching tests a value's shape and binds pieces of it. The switch expression turns classification into data:

public static string Describe(object o) => o switch
{
    int n when n < 0            => "negative int",
    int n and > 100             => "big int",
    int                         => "small int",
    string { Length: 0 }        => "empty string",
    string s                    => $"string of {s.Length}",
    null                        => "nothing",
    _                           => "unknown"
};

Building blocks, composable everywhere:

  • Type pattern int n โ€” test + bind.
  • Property pattern string { Length: 0 }, Point { X: > 0, Y: > 0 }.
  • Relational > 100, logical and/or/not.
  • Constant null, enum values, literals.
  • List patterns (C# 11): [1, .., var last] matches a sequence's shape.

Exhaustiveness and hierarchy

With enums and closed hierarchies, the compiler can prove you covered every case โ€” miss one and you get a warning, not a runtime bug. That is why switching on a Shape union beats if/else chains: the type system participates in correctness. Add _ too early and you silence that protection โ€” reach for it last.

public enum LoadState { Idle, Loading, Ready, Failed }
public static bool IsBusy(LoadState s) => s switch
{
    LoadState.Loading => true,
    LoadState.Idle or LoadState.Ready or LoadState.Failed => false,
    _ => throw new ArgumentOutOfRangeException(nameof(s))  // future-proofing
};

Tuples and deconstruction

Tuples group ad-hoc values; deconstruction unpacks anything with a Deconstruct method (all records have one):

(string name, int score) = ("ann", 92);
var (min, max) = (nums.Min(), nums.Max());
foreach (var (key, count) in dict)   // KeyValuePair deconstructs too
    Console.WriteLine($"{key}: {count}");

Switch on tuples for decision tables that read like tables:

public static string Grade(int score, bool attended) => (score, attended) switch
{
    ( >= 90, true)  => "A+",
    ( >= 90, false) => "A",
    ( >= 80, _)     => "B",
    _               => "C"
};

Check your understanding

  • Why is _ => ... a double-edged sword? (Catches future cases silently.)
  • When does a property pattern beat a guard clause? (When classifying, not validating.)
  • What does foreach (var (k, v) in dict) rely on? (KeyValuePair.Deconstruct.)

โšก Now practice

Ready to Code
Pattern GymSwitch expressions as design, tuples and deconstruction as data flow.
2 challenges ยท ยท ~24 min