Back to Home

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

C# Example Code
// 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

C# Example Code
// 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

C# Example Code
// 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

C# Example Code
// 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

C# Example Code
// 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.

C# Example Code
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); // Inactive

When Guards

Add a when clause to a pattern to filter matches with an extra condition.

C# Example Code
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: -5

Property Patterns

Match on the properties of an object directly in the switch arm.

C# Example Code
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 axis

Real-World Example: HTTP Status Codes

C# Example Code
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

C# Example Code
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

C# in Depth book cover

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.