C#
switch statement
multi-variable
programming
software development

Multi-variable switch statement in C

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

C# 8.0 introduced tuple patterns and property patterns in switch expressions, enabling multi-variable switching in a single statement. Before C# 8, switch only matched a single value. Now you can switch on tuples like (x, y), combining multiple variables into one pattern match. This eliminates nested if/else chains and makes complex conditional logic readable and concise.

Traditional Single-Variable Switch

csharp
1// C# 7 and earlier — single variable only
2string GetDiscount(string memberType)
3{
4    switch (memberType)
5    {
6        case "Gold": return "30% off";
7        case "Silver": return "20% off";
8        case "Bronze": return "10% off";
9        default: return "No discount";
10    }
11}

Tuple Pattern Switch (C# 8+)

Switch on multiple variables by wrapping them in a tuple:

csharp
1string GetShippingCost(string memberType, string region) => (memberType, region) switch
2{
3    ("Gold", "Domestic")     => "Free",
4    ("Gold", "International") => "$5",
5    ("Silver", "Domestic")    => "$3",
6    ("Silver", "International") => "$10",
7    ("Bronze", _)             => "$15",  // Any region
8    (_, "Domestic")           => "$8",   // Any member type
9    _                         => "$20",  // Default
10};
11
12Console.WriteLine(GetShippingCost("Gold", "International"));  // $5
13Console.WriteLine(GetShippingCost("Bronze", "Domestic"));      // $15

The _ discard matches any value. Patterns are evaluated top to bottom — the first match wins.

Switch Expression with Guards (when)

Add conditions to patterns using when:

csharp
1string ClassifyTransaction(string type, decimal amount) => (type, amount) switch
2{
3    ("Credit", > 10000)  => "High-value credit",
4    ("Credit", > 1000)   => "Medium credit",
5    ("Credit", _)        => "Small credit",
6    ("Debit", > 5000)    => "Large debit",
7    ("Debit", _)         => "Standard debit",
8    _ => "Unknown transaction"
9};
10
11// With explicit when clause
12string Evaluate(int x, int y) => (x, y) switch
13{
14    (> 0, > 0) => "Both positive",
15    (< 0, < 0) => "Both negative",
16    (0, 0)     => "Origin",
17    var (a, b) when a == -b => "Mirror points",
18    _          => "Mixed"
19};

Property Pattern Matching

Match against object properties:

csharp
1record Order(string Status, decimal Total, string CustomerType);
2
3string GetAction(Order order) => order switch
4{
5    { Status: "Pending", Total: > 1000 }                    => "Requires manager approval",
6    { Status: "Pending", CustomerType: "VIP" }              => "Auto-approve",
7    { Status: "Pending" }                                     => "Standard review",
8    { Status: "Shipped" }                                     => "Track delivery",
9    { Status: "Delivered", Total: > 500 }                    => "Request feedback",
10    _                                                          => "No action"
11};

Nested Patterns

csharp
1record Address(string Country, string State);
2record Customer(string Name, Address Address, bool IsPremium);
3
4decimal GetTaxRate(Customer customer) => customer switch
5{
6    { Address.Country: "US", Address.State: "CA" } => 0.0725m,
7    { Address.Country: "US", Address.State: "TX" } => 0.0625m,
8    { Address.Country: "US" }                       => 0.05m,
9    { Address.Country: "UK" }                       => 0.20m,
10    { IsPremium: true }                              => 0.0m,
11    _                                                 => 0.10m,
12};

Switch Statement (Not Expression)

The switch statement form uses case with tuple patterns:

csharp
1void ProcessInput(ConsoleKey key, bool shiftPressed)
2{
3    switch (key, shiftPressed)
4    {
5        case (ConsoleKey.Enter, false):
6            Submit();
7            break;
8        case (ConsoleKey.Enter, true):
9            NewLine();
10            break;
11        case (ConsoleKey.Escape, _):
12            Cancel();
13            break;
14        case (ConsoleKey.Tab, false):
15            NextField();
16            break;
17        case (ConsoleKey.Tab, true):
18            PreviousField();
19            break;
20        default:
21            HandleKey(key);
22            break;
23    }
24}

Three or More Variables

Tuples support any number of elements:

csharp
1string DescribeWeather(string season, int temp, bool raining) => (season, temp, raining) switch
2{
3    ("Summer", > 35, _)        => "Extreme heat warning",
4    ("Summer", > 25, false)    => "Perfect beach day",
5    ("Summer", _, true)        => "Summer rain",
6    ("Winter", < 0, _)         => "Freezing conditions",
7    ("Winter", _, true)        => "Snow likely",
8    ("Spring", > 15, false)    => "Nice spring day",
9    _                           => "Check forecast"
10};

Replacing Nested If/Else

Before (nested ifs):

csharp
1// Hard to read
2if (role == "Admin" && isActive)
3    return "Full access";
4else if (role == "Admin" && !isActive)
5    return "Suspended admin";
6else if (role == "User" && isActive && isVerified)
7    return "Verified user";
8else if (role == "User" && isActive)
9    return "Unverified user";
10else
11    return "No access";

After (tuple switch):

csharp
1string GetAccess(string role, bool isActive, bool isVerified) =>
2    (role, isActive, isVerified) switch
3    {
4        ("Admin", true, _)     => "Full access",
5        ("Admin", false, _)    => "Suspended admin",
6        ("User", true, true)   => "Verified user",
7        ("User", true, false)  => "Unverified user",
8        _                       => "No access"
9    };

Common Pitfalls

  • Unreachable patterns: Patterns are evaluated top to bottom. A broader pattern above a specific one makes the specific one unreachable. The compiler warns about this — always place specific patterns before general ones.
  • Missing exhaustiveness: Switch expressions must be exhaustive — all possible input combinations must be handled. Omitting the _ default when not all cases are covered produces a compiler warning. At runtime, an unmatched input throws SwitchExpressionException.
  • C# version requirement: Tuple patterns require C# 8.0+, property patterns require C# 8.0+, and relational patterns (> 0, < 10) require C# 9.0+. Verify your project's LangVersion in .csproj.
  • Mutable tuple values: If the switched variables change between evaluation, the result is based on values at the time of the switch, not when the result is used. Capture values in local variables first if mutability is a concern.
  • Overusing switch expressions: For simple two-way conditions, if/else is more readable. Switch expressions shine when there are three or more combined conditions — not for simple boolean checks.

Summary

  • Use tuple patterns (x, y) switch { ... } to match multiple variables in a single switch expression (C# 8+)
  • Combine with relational patterns (> 0, < 10) and when guards for complex conditions (C# 9+)
  • Property patterns match against object properties without destructuring
  • Place specific patterns before general ones — first match wins
  • Switch expressions must be exhaustive; always include a _ default case

Course illustration
Course illustration

All Rights Reserved.