C# Programming Tutorial 0/45 lessons ~6 min read Lesson 8

    Switch Expressions

    C# 8+ switch expressions replace verbose switch statements with concise, expression-oriented syntax that returns a value.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    C# 8+ switch expressions replace verbose switch statements with concise, expression-oriented syntax that returns a value. Combined with relational patterns, logical patterns (and/or), and property patterns, they power modern API mapping and domain logic.

    Exhaustiveness checking warns when you miss enum cases — critical when adding new payment types or diagnosis codes. Switch expressions appear constantly in ASP.NET Core minimal API result mapping and functional-style service layers.

    This lesson contrasts classic switch, switch expressions, and when to reach for if/else instead.

    The story

    A logistics company quotes shipping rates based on destination zone, package weight, and whether the customer paid for express delivery. A domestic envelope under one kilogram costs a flat fee; heavier domestic parcels add per-kilo surcharges; international shipments use an entirely different formula.

    Switch expressions let you express that pricing table as a single expression that returns a decimal — cleaner than a dozen nested if statements and easier to unit test.

    Understanding the topic

    Key concepts

    • Switch expression syntax: value switch { pat => result, _ => default }
    • Arms must cover all cases or include discard _.
    • Property patterns: obj is { Status: Active, Balance: > 0 }
    • Relational patterns: x is > 0 and < 100
    • Tuple switch for multi-value dispatch.
    • Switch statements still valid for void side-effect branches.
    text
    flowchart LR
    Input[Value] --> Switch{switch expression}
    Switch --> Arm1[Pattern Arm 1]
    Switch --> Arm2[Pattern Arm 2]
    Switch --> Default[_ default]

    Step-by-step explanation

    1. Evaluate switch input expression once.
    2. Match arms top-to-bottom; first match wins.
    3. All arms return same type in expression form.
    4. Compiler enforces enum exhaustiveness when possible.
    5. when guards add extra boolean conditions to patterns.
    6. Combine with switch statement for mixed case bodies with break.

    Practical code example

    Enterprise shipping rate calculator with relational and property patterns:

    csharp
    namespace TechLearningPro.SwitchExpressions;
    public record Shipment(string Zone, decimal WeightKg, bool IsExpress);
    public static class ShippingCalculator
    {
    public static decimal CalculateRate(Shipment s) => s switch
    {
    { WeightKg: <= 0 } => throw new ArgumentException("Weight must be positive."),
    { Zone: "DOMESTIC", WeightKg: <= 1, IsExpress: false } => 5.99m,
    { Zone: "DOMESTIC", WeightKg: <= 1, IsExpress: true } => 12.99m,
    { Zone: "DOMESTIC", WeightKg: > 1 and <= 10 } => 5.99m + (s.WeightKg - 1) * 1.50m,
    { Zone: "INTERNATIONAL" } => 24.99m + s.WeightKg * 4.00m,
    _ => throw new ArgumentException(
    quot;Unknown zone: {s.Zone}")
    };
    }

    Line-by-line code explanation

    • public record Shipment(string Zone, decimal WeightKg, bool IsExpress) bundles the inputs that determine shipping cost.
    • CalculateRate(Shipment s) => s switch starts a switch expression on the shipment record.
    • { WeightKg: <= 0 } is a property pattern that rejects invalid weights first.
    • throw new ArgumentException(...) in a switch arm stops invalid data immediately.
    • { Zone: "DOMESTIC", WeightKg: <= 1, IsExpress: false } matches lightweight standard domestic packages.
    • => 5.99m returns the flat rate for that arm — switch arms produce values directly.
    • { Zone: "DOMESTIC", WeightKg: > 1 and <= 10 } combines relational patterns with and.
    • 5.99m + (s.WeightKg - 1) * 1.50m adds a per-kilo surcharge above one kilogram.
    • { Zone: "INTERNATIONAL" } catches all international shipments regardless of weight tier.
    • _ => throw new ArgumentException(...) is the discard arm for unknown zones.

    Key takeaway: Property patterns destructure records inline. and combines relational constraints. Throw in discard arm documents invalid zones.

    Real-world use

    Where you'll use this in production

    • HTTP status to ProblemDetails mapping in APIs.
    • State machine transitions in order fulfillment.
    • Error code to user message localization.
    • Pricing tier calculation by customer segment.

    Best practices

    • Prefer switch expressions for value-returning mappings.
    • Keep arms readable — extract complex logic to methods.
    • Handle new enum values — compiler helps if not exhaustive.
    • Use _ discard for true defaults, not silent swallowing.
    • Document thrown exceptions for unmatched inputs.

    Common mistakes

    • Mixing statement and expression syntax incorrectly.
    • Forgetting all enum cases — runtime fall-through bugs.
    • Side effects inside switch expressions — hard to test.
    • Overly clever patterns harming maintainability.

    Advanced interview questions

    Q1BeginnerSwitch expression vs switch statement?
    Expression returns value, no break; statement executes cases with break/return.
    Q2BeginnerWhat is the discard pattern _?
    Catch-all arm when no other pattern matches.
    Q3IntermediateProperty pattern example?
    { Name: "Admin", IsActive: true } matches object with those property values.
    Q4Intermediatewhen clause purpose?
    Additional boolean guard on a pattern arm.
    Q5AdvancedDesign exhaustiveness for payment method enum adding Crypto.
    Switch on enum — compiler warns missing Crypto arm; add arm with fee logic; unit test all methods.

    Summary

    Switch expressions are concise, return values, and support rich patterns. Property and relational patterns reduce casting boilerplate. Use for mapping discrete inputs to outputs in domain logic. Compiler exhaustiveness catches missing enum cases. Next: loops for iteration and aggregation.

    Ready to mark this lesson complete?Track your journey across the entire course.