<style> .reveal-up, .reveal-left, .reveal-right, .reveal-stagger > * { opacity: 1 !important; transform: none !important; } </style>
  1. Learn
  2. C#
  3. Functional C# and LINQ
All lessons in this course

Lesson 43 of 60 14 minIntermediate

Pattern matching

Test the shape of data and pull values out in one step: type, property, relational, logical and list patterns with is and switch.

Code often asks several questions at once: “is this object a Beam, and is it longer than 8 m?”. Pattern matching lets you test a value’s type and contents, and capture parts of it into variables, in a single readable expression.

is with a type pattern

TypePattern.cs
object item = new Beam("B1", 9.5); // old way: test, then castif (item is Beam){    var b1 = (Beam)item;    Console.WriteLine(b1.Mark);} // pattern: test and declare a typed variable togetherif (item is Beam b && b.Length > 8)    Console.WriteLine($"{b.Mark} is a long beam"); record Beam(string Mark, double Length);
Output
B1
B1 is a long beam

switch expressions with patterns

Interactive

Which pattern matches?

Patterns are tested top to bottom; the first one that matches wins. Pick a value for obj.

object? obj =
Describe.cs
string Describe(object? obj) => obj switch{    null => "nothing",    Beam { Length: > 8 } => "long beam",    Beam b => $"beam {b.Length} m",    Column => "column",    int n when n < 0 => "negative int",    int and (> 0 and < 100) => "small int",    string { Length: 0 } => "empty text",    string s => $"text: {s}",    _ => "something else"};
Output
long beam
nullno match
Beam { Length: > 8 }MATCH
PatternMatches when…Example
constantequal to a constantnull, 0, "IPE300"
typethe value is that type (declares a variable)Beam b
relationalcompared to a constant> 8, <= 0
logicalcombined with and / or / not>= 1 and <= 5, not null
propertyproperties match nested patterns{ Length: > 8, Profile: "IPE300" }
discardanything_
when guardan extra boolean conditionint n when n % 2 == 0

Property patterns on real data

Properties.cs
static string Classify(Beam b) => b switch{    { Length: <= 0 } => "invalid",    { Profile: "HEA200" or "HEA300", Length: > 6 } => "heavy span",    { Length: > 8 } => "long",    { Length: < 2 } => "stub",    _ => "standard"}; Console.WriteLine(Classify(new Beam("B1", "HEA200", 7.5)));Console.WriteLine(Classify(new Beam("B2", "IPE200", 1.2))); record Beam(string Mark, string Profile, double Length);
Output
heavy span
stub

not null

NotNull.cs
if (selected is not null) Highlight(selected);if (input is not (null or ""))  Process(input);

Tuple patterns

TuplePattern.cs
static string Rps(string a, string b) => (a, b) switch{    ("rock", "scissors") or ("scissors", "paper") or ("paper", "rock") => "A wins",    var (x, y) when x == y => "draw",    _ => "B wins"};Console.WriteLine(Rps("paper", "rock"));
Output
A wins

List patterns (C# 11)

ListPattern.cs
static string Describe(int[] v) => v switch{    [] => "empty",    [var only] => $"one item: {only}",    [var first, .., var last] => $"from {first} to {last}",};Console.WriteLine(Describe(new[] { 4, 8, 15, 16 }));
Output
from 4 to 16
Quick check

What does obj is Beam { Length: > 6 } b do?

Quick check

In a switch expression, why should _ => … come last?

Practice

Write static string Shipping(decimal weightKg, bool express) with a switch expression on the tuple (weightKg, express): ≤ 1 kg express → "Rs 150", ≤ 1 kg → "Rs 60", ≤ 10 kg express → "Rs 400", ≤ 10 kg → "Rs 180", anything heavier → "Freight". Negative weight → throw.

Show the solution
Solution.cs
static string Shipping(decimal weightKg, bool express) => (weightKg, express) switch{    ( < 0, _) => throw new ArgumentOutOfRangeException(nameof(weightKg)),    ( <= 1, true) => "Rs 150",    ( <= 1, false) => "Rs 60",    ( <= 10, true) => "Rs 400",    ( <= 10, false) => "Rs 180",    _ => "Freight"}; Console.WriteLine(Shipping(0.5m, true));Console.WriteLine(Shipping(7m, false));Console.WriteLine(Shipping(25m, true));
Output
Rs 150
Rs 180
Freight

Remember

  • is and switch can test type, values and properties in one expression.
  • Patterns: type, constant, relational, and/or/not, property, tuple, list, _.
  • Arms are tested top to bottom; put specific ones first and _ last.
  • Patterns declare typed variables, removing manual casts.
0 of 60 lessons completed