switch
When one value decides between many choices, a switch is clearer than a long else if chain. C# has two forms: the classic switch statement, which runs code for a matching case, and the newer switch expression, which produces a value. Both can match patterns, not just constants.
The switch statement
int day = 3; switch (day) { case 1: Console.WriteLine("Monday"); break; case 2: Console.WriteLine("Tuesday"); break; case 3: Console.WriteLine("Wednesday"); break; default: Console.WriteLine("Another day"); break; }
Wednesday
The value in parentheses is compared with each case. default handles anything that didn't match; it's optional, but usually a good idea.
No fall-through
In C and Java, forgetting break lets execution "fall through" into the next case — a classic bug. C# makes it a compile error: every section must end with break, return, throw or similar.
int level = 1; switch (level) { case 1: Console.WriteLine("Beginner"); case 2: Console.WriteLine("Intermediate"); break; }
Program.cs(4,5): error CS0163: Control cannot fall through from one case label ('case 1:') to anotherTo share code between values, stack the labels with nothing between them:
string month = "Feb"; switch (month) { case "Dec": case "Jan": case "Feb": Console.WriteLine("Winter"); break; case "Jun": case "Jul": case "Aug": Console.WriteLine("Summer"); break; default: Console.WriteLine("Spring or autumn"); break; }
Winter
As this shows, switch works with strings as well as numbers, characters and enums.
Patterns and when guards
A case can match a pattern rather than a single value — for example a range — and a when clause adds an extra condition:
int[] temperatures = [-5, 8, 19, 27, 38]; foreach (int t in temperatures) { switch (t) { case < 0: Console.WriteLine($"{t}: freezing"); break; case >= 0 and < 15: Console.WriteLine($"{t}: cold"); break; case < 25: Console.WriteLine($"{t}: mild"); break; case var hot when hot > 35: Console.WriteLine($"{t}: dangerously hot"); break; default: Console.WriteLine($"{t}: warm"); break; } }
-5: freezing 8: cold 19: mild 27: warm 38: dangerously hot
Cases are tested from top to bottom, so case < 25 only sees values that weren't already caught.
switch expressions
Often each case just produces a value. A switch expression says that directly: the value comes first, then switch, then pattern => result arms separated by commas. The underscore _ (the discard) matches anything:
int day = 6; string kind = day switch { 6 or 7 => "weekend", >= 1 and <= 5 => "weekday", _ => "invalid day", }; Console.WriteLine(kind);
weekend
Switch expressions are compact, and because they produce a value they work anywhere an expression does — in a return, an argument or string interpolation:
foreach (decimal amount in new[] { 12m, 75m, 240m }) { decimal discount = amount switch { >= 200 => 0.15m, >= 50 => 0.05m, _ => 0m, }; Console.WriteLine($"{amount}: discount {discount:P0}, pay {amount * (1 - discount)}"); }
12: discount 0%, pay 12 75: discount 5%, pay 71.25 240: discount 15%, pay 204.00
Notice that decimal results keep the number of decimal places produced by the calculation (204.00, but 12). Lesson 18 shows how to format output to a fixed number of places.
Missing cases
A switch expression must produce a value for every input. If the compiler sees inputs that no arm handles, it warns you — and at run time an unmatched value throws an exception that reports the value:
int code = 3; string name = code switch { 1 => "one", 2 => "two", }; Console.WriteLine(name);
Program.cs(2,20): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '0' is not covered. Unhandled exception. System.Runtime.CompilerServices.SwitchExpressionException: Non-exhaustive switch expression failed to match its input. Unmatched value was 3.
Add a _ => arm (or one that throws a clear exception) to fix it.
Switching on several values
Wrap several values in a tuple to switch on all of them at once:
string Play(string a, string b) => (a, b) switch { _ when a == b => "draw", ("rock", "scissors") or ("scissors", "paper") or ("paper", "rock") => "player 1 wins", _ => "player 2 wins", }; Console.WriteLine(Play("rock", "scissors")); Console.WriteLine(Play("rock", "paper")); Console.WriteLine(Play("paper", "paper"));
player 1 wins player 2 wins draw
Which form to use
- switch expression — when each case computes a value. This is the modern default.
- switch statement — when cases run several statements or have side effects like printing and saving.
- if / else if — when the conditions test different variables or unrelated things.
Try it yourself
Turn an HTTP status code into a description. Add a case for 404 and a range for server errors (500–599).
200: OK 301: Redirect 404: Client error 503: Unknown 999: Unknown