Pattern matching for polymorphism
Learn polymorphic dispatch with switch expressions and type patterns.
switch expressions and type patterns
The modern C# switch expression with type patterns performs polymorphic dispatch at the expression level. Code that handles an Animal by its runtime type becomes a single expression.
Example: string sound = animal switch { Dog d => "Woof", Cat c => "Meow", _ => "?" };. Here Dog d is a type pattern: on match, the variable d binds to the object. _ is the default discard arm. Because a switch expression produces a value, it can be assigned to a variable.
Extra conditions with when
Sometimes the type alone is not enough; you need an extra condition inside the same type. For that you use a when clause. An arm like Dog d when d.Age > 5 catches only dogs older than five.
The when clause filters after the type pattern matches. This lets you write finer discriminating arms. Order matters: arms are tried top to bottom, and the first match runs. Always put the default arm last. Otherwise the compiler warns you.
Exercise Produce sounds with a switch expression
Define an Animal class. Define Dog : Animal and Cat : Animal. In Program write static string Sound(Animal a) using a switch expression: return "Woof" for Dog, "Meow" for Cat, "?" for the default. In Main call Sound with a Dog, a Cat, an Animal and print each result.
Show example solution
Write static string Sound(Animal a) { return a switch { Dog d => "Woof", Cat c => "Meow", _ => "?" }; }. In Main add Console.WriteLine(Sound(new Dog())); Console.WriteLine(Sound(new Cat())); Console.WriteLine(Sound(new Animal()));
Example solution:
using System;
class Animal { }
class Dog : Animal { }
class Cat : Animal { }
class Program
{
static string Sound(Animal a)
{
return a switch
{
Dog d => "Woof",
Cat c => "Meow",
_ => "?"
};
}
static void Main()
{
Console.WriteLine(Sound(new Dog()));
Console.WriteLine(Sound(new Cat()));
Console.WriteLine(Sound(new Animal()));
}
}
Test yourself
-
Which is the default arm in a switch expression?
var s = a switch { Dog d => "Woof", _ => "?" };- default =>
- else =>
- null =>
- _ =>
Show answer
_ => — Correct. _ (discard) is the default arm of a switch expression.
-
Bind a variable with a type pattern
if (animal ____ Dog d) { d.Bark(); }Show answer
if (animal is Dog d) { d.Bark(); } -
Match each pattern piece to its meaning
- switch
- Branches by expression
- =>
- Arrow expression
- is
- Tests a type pattern
- when
- Adds a filter