Switch Expressions vs Switch Statements in C# 8
C# 8 introduced switch expressions, providing a concise, expression-based alternative to the traditional switch statement. While traditional switch statements execute blocks of procedural code based on matching conditions, switch expressions evaluate patterns to produce a single value directly. This article compares how switch expressions work against traditional switch statements, highlighting key syntax changes, functional differences, and best practices for writing cleaner, more expressive C# code.
Core Differences: Expressions vs. Statements
The fundamental difference lies in their language classification:
- Switch Statement: A control-flow construct that
executes code blocks. It does not inherently return a value, often
requiring variable mutation inside cases and manual flow control via
break,return, orgoto. - Switch Expression: An expression that yields a value directly. It is assigned to a variable or returned directly from a method, eliminating boilerplate and intermediate state assignment.
Syntax Comparison
Traditional switch statements require repetitive keywords like
case, break, and default. Switch
expressions streamline this using lambda-like arrows
(=>) and comma-separated arms.
Traditional Switch Statement (C# 7 and earlier)
public string GetDayType(DayOfWeek day)
{
string result;
switch (day)
{
case DayOfWeek.Saturday:
case DayOfWeek.Sunday:
result = "Weekend";
break;
case DayOfWeek.Monday:
case DayOfWeek.Tuesday:
case DayOfWeek.Wednesday:
case DayOfWeek.Thursday:
case DayOfWeek.Friday:
result = "Weekday";
break;
default:
throw new ArgumentOutOfRangeException(nameof(day), "Invalid day");
}
return result;
}C# 8 Switch Expression
public string GetDayType(DayOfWeek day) => day switch
{
DayOfWeek.Saturday or DayOfWeek.Sunday => "Weekend",
DayOfWeek.Monday or DayOfWeek.Tuesday or DayOfWeek.Wednesday
or DayOfWeek.Thursday or DayOfWeek.Friday => "Weekday",
_ => throw new ArgumentOutOfRangeException(nameof(day), "Invalid day")
};Key Functional Changes
1. Inverted Target Syntax
In a traditional statement, the keyword precedes the expression being
evaluated: switch (target). In a switch expression, the
target precedes the keyword: target switch { ... }.
2. The Discard Pattern
(_) Replaces default
Traditional switches use the default: label as a
catch-all. Switch expressions use the underscore discard pattern
(_ => ...) to handle any unmatched cases.
3. Exhaustiveness Checking
Because switch expressions produce a value, the compiler enforces
exhaustiveness. If a switch expression does not cover all possible input
values and lacks a discard (_) case, the compiler generates
a warning. At runtime, an unhandled value throws an
InvalidOperationException (specifically, a
SwitchExpressionException). Traditional switch statements
simply fall through without warning if cases are unhandled.
4. Advanced Pattern Matching
Switch expressions integrate cleanly with C# pattern matching, allowing property matching, tuple matching, and positional matching with minimal syntax:
public decimal CalculateDiscount(Order order) => order switch
{
{ IsPremiumCustomer: true, TotalAmount: > 100m } => 0.20m,
{ IsPremiumCustomer: true } => 0.10m,
{ TotalAmount: > 100m } => 0.05m,
_ => 0m
};When to Use Which
- Use Switch Expressions when your goal is to evaluate input data and map it directly to a single value, object, or result. They are ideal for pure functions, data transformations, and state-to-value mappings.
- Use Switch Statements when you need to execute
multi-step operations, trigger side effects, perform complex logging per
case, or handle asynchronous calls using
awaitwithin individual branches.