How to use switch expressions in C#
Switch expressions in C# 8.0+ provide a concise syntax for pattern matching. Unlike switch statements, they return a value directly and use => instead of case and break.
You can use patterns like type patterns, relational patterns, and logical patterns. The underscore serves as a discard pattern, matching anything (similar to default).
Switch expressions are expressions, not statements, so they must return a value and can be used inline or assigned to variables.
Basic Switch Expression
// Basic switch expression
int dayNumber = 3;
string dayName = dayNumber switch
{
1 => "Monday",
2 => "Tuesday",
3 => "Wednesday",
4 => "Thursday",
5 => "Friday",
6 => "Saturday",
7 => "Sunday",
_ => "Invalid day"
};
Console.WriteLine($"Day {dayNumber}: {dayName}");Type Patterns
// With type patterns
object obj = "Hello";
string result = obj switch
{
int i => $"Integer: {i}",
string s => $"String: {s}",
double d => $"Double: {d}",
_ => "Unknown type"
};
Console.WriteLine(result);Relational Patterns
// Relational patterns
int score = 85;
string grade = score switch
{
>= 90 => "A",
>= 80 => "B",
>= 70 => "C",
>= 60 => "D",
_ => "F"
};
Console.WriteLine($"Score {score}: Grade {grade}");Logical Patterns
// Multiple conditions (logical patterns)
int temperature = 75;
string weather = temperature switch
{
< 32 => "Freezing",
>= 32 and < 50 => "Cold",
>= 50 and < 70 => "Cool",
>= 70 and < 85 => "Warm",
>= 85 => "Hot"
};
Console.WriteLine($"{temperature}°F is {weather}");Tuple Patterns
// With tuples
string GetQuadrant(int x, int y) => (x, y) switch
{
(> 0, > 0) => "Quadrant I",
(< 0, > 0) => "Quadrant II",
(< 0, < 0) => "Quadrant III",
(> 0, < 0) => "Quadrant IV",
(0, 0) => "Origin",
_ => "On axis"
};
Console.WriteLine($"Point (3, 4): {GetQuadrant(3, 4)}");
Console.WriteLine($"Point (-2, 5): {GetQuadrant(-2, 5)}");Switch Statement vs Switch Expression
Switch expressions are more concise than switch statements and enforce that every arm returns a value. The compiler warns if a case is unhandled.
int status = 2;
// Switch statement — verbose, imperative
string descriptionOld;
switch (status)
{
case 1: descriptionOld = "Active"; break;
case 2: descriptionOld = "Inactive"; break;
case 3: descriptionOld = "Pending"; break;
default: descriptionOld = "Unknown"; break;
}
// Switch expression (C# 8+) — concise, must return a value
string descriptionNew = status switch
{
1 => "Active",
2 => "Inactive",
3 => "Pending",
_ => "Unknown"
};
Console.WriteLine(descriptionOld); // Inactive
Console.WriteLine(descriptionNew); // InactiveWhen Guards
Add a when clause to a pattern to filter matches with an extra condition.
int value = 15;
string category = value switch
{
< 0 => "Negative",
0 => "Zero",
< 10 => "Small",
int n when n % 2 == 0 => "Large even",
_ => "Large odd"
};
Console.WriteLine(category); // Large odd
// when with type patterns
object obj = -5;
string label = obj switch
{
int n when n < 0 => $"Negative int: {n}",
int n when n == 0 => "Zero",
int n => $"Positive int: {n}",
string s => $"String: \"{s}\"",
_ => "Other"
};
Console.WriteLine(label); // Negative int: -5Property Patterns
Match on the properties of an object directly in the switch arm.
var order = new { Total = 250.00m, IsPremiumMember = true };
string discount = order switch
{
{ Total: >= 500 } => "20% discount",
{ Total: >= 200, IsPremiumMember: true } => "15% discount",
{ Total: >= 100 } => "10% discount",
_ => "No discount"
};
Console.WriteLine(discount); // 15% discount
// Nested property pattern
var point = new { X = 0, Y = 5 };
string quadrant = point switch
{
{ X: > 0, Y: > 0 } => "Quadrant I",
{ X: < 0, Y: > 0 } => "Quadrant II",
{ X: < 0, Y: < 0 } => "Quadrant III",
{ X: > 0, Y: < 0 } => "Quadrant IV",
{ X: 0, Y: 0 } => "Origin",
_ => "On an axis"
};
Console.WriteLine(quadrant); // On an axisReal-World Example: HTTP Status Codes
static string DescribeStatus(int code) => code switch
{
200 => "OK",
201 => "Created",
204 => "No Content",
301 => "Moved Permanently",
400 => "Bad Request",
401 => "Unauthorized",
403 => "Forbidden",
404 => "Not Found",
409 => "Conflict",
429 => "Too Many Requests",
>= 500 and < 600 => $"Server Error ({code})",
_ => $"Unknown ({code})"
};
Console.WriteLine(DescribeStatus(200)); // OK
Console.WriteLine(DescribeStatus(404)); // Not Found
Console.WriteLine(DescribeStatus(503)); // Server Error (503)Real-World Example: Discount Calculator
record Customer(string Tier, int YearsActive, decimal OrderTotal);
static decimal GetDiscount(Customer c) => c switch
{
{ Tier: "Gold", YearsActive: >= 5 } => 0.25m,
{ Tier: "Gold" } => 0.20m,
{ Tier: "Silver", OrderTotal: >= 200 } => 0.15m,
{ Tier: "Silver" } => 0.10m,
{ YearsActive: >= 10 } => 0.08m,
_ => 0.05m
};
var c1 = new Customer("Gold", 7, 150m);
var c2 = new Customer("Silver", 2, 250m);
var c3 = new Customer("Bronze", 1, 50m);
Console.WriteLine($"C1: {GetDiscount(c1):P0}"); // C1: 25%
Console.WriteLine($"C2: {GetDiscount(c2):P0}"); // C2: 15%
Console.WriteLine($"C3: {GetDiscount(c3):P0}"); // C3: 5%Take It Further

The book that turns good C# developers into great ones. Written by Stack Overflow's #1 contributor.
C# in Depth — 4th Edition · Jon Skeet
Get it on Amazon →As an Amazon Associate I earn from qualifying purchases.