switch Statement / switch Expression (C#)
The switch statement provides a concise way to write multi-branch conditionals. C# 8 and later also introduced the switch expression. You can use pattern matching on strings, enums, types, and more, replacing long chains of if / else if with cleaner, more readable code.
Syntax
switch (variable or expression) {
case value1:
// Executed when the value matches value1.
break;
case value2:
// Executed when the value matches value2.
break;
default:
// Executed when no case matches.
break;
}
// Multiple values can be grouped into a single case.
switch (variable) {
case value1:
case value2:
// Executed when the value matches either value1 or value2.
break;
default:
break;
}
// Use goto case to explicitly fall through to another case.
switch (variable) {
case value1:
// After processing, jumps to the value2 case.
goto case value2;
case value2:
// Executed whether reached via goto from value1, or matched directly.
break;
}
var result = variable switch {
value1 => returnValue1,
value2 => returnValue2,
_ => defaultValue
};
// A when guard adds an extra condition to a pattern arm.
var result = variable switch {
type v when condition => returnValue,
_ => defaultValue
};
switch statement vs. switch expression
| Feature | switch statement | switch expression (C# 8+) |
|---|---|---|
| Syntax | case / break / default | Arrow (=>) returns a value. |
| Use case | Executing multiple statements per branch. | Selecting and returning a single value. |
| Fall-through | Explicit via goto case. | Not supported — each arm is independent. |
| Default equivalent | default: | _ => (wildcard) |
| when guard | case value when condition: | value when condition => |
| Exhaustiveness check | None. | The compiler may warn about unhandled cases. |
Sample Code
SwitchBasic.cs
using System;
class SwitchBasic {
static void Main() {
// Determines the skill of a member by name.
string name = "member_3";
switch (name) {
case "member_2":
Console.WriteLine(name + " handles skill_a.");
break;
case "member_3":
Console.WriteLine(name + " handles skill_b."); // This branch executes.
break;
case "member_4":
Console.WriteLine(name + " handles skill_c.");
break;
default:
Console.WriteLine(name + "'s skill is unknown.");
break;
}
string member = "member_4";
switch (member) {
case "member_2":
case "member_3":
case "member_4":
Console.WriteLine(member + " is a Group A member."); // This branch executes.
break;
case "member_5":
Console.WriteLine(member + " is a Group B member.");
break;
default:
Console.WriteLine(member + "'s group is unknown.");
break;
}
// Transfers control from one case to another.
string level = "S";
switch (level) {
case "S":
Console.WriteLine("Recognized as Level S.");
goto case "A"; // Jumps to the A case.
case "A":
Console.WriteLine("Authorized for advanced tasks."); // Executed for both S and A.
break;
case "B":
Console.WriteLine("Capable of handling standard tasks.");
break;
default:
Console.WriteLine("No level has been assigned.");
break;
}
}
}
This produces the following output:
dotnet script SwitchBasic.cs member_3 handles skill_b. member_4 is a Group A member. Recognized as Level S. Authorized for advanced tasks.
SwitchEnum.cs
using System;
// An enum representing skill types.
enum SkillType {
Analysis, // Data analysis
Planning, // Project planning
Design, // System design
Review, // Code review
Unknown // Unknown
}
class SwitchEnum {
static void Main() {
SkillType type = SkillType.Design;
switch (type) {
case SkillType.Analysis:
Console.WriteLine("Specializes in data collection and analysis.");
break;
case SkillType.Planning:
Console.WriteLine("Handles project planning.");
break;
case SkillType.Design:
Console.WriteLine("Handles system design."); // This branch executes.
break;
case SkillType.Review:
Console.WriteLine("Handles deliverable reviews.");
break;
default:
Console.WriteLine("Skill is unknown.");
break;
}
SkillType[] types = {
SkillType.Analysis,
SkillType.Review,
SkillType.Unknown
};
foreach (SkillType t in types) {
string description = t switch {
SkillType.Analysis => "A fundamental data analysis skill.",
SkillType.Planning => "A project planning skill.",
SkillType.Design => "The foundation of system design.",
SkillType.Review => "A skill for reviewing deliverables.",
_ => "Skill is unknown."
};
Console.WriteLine(t + ": " + description);
}
}
}
This produces the following output:
dotnet script SwitchEnum.cs Handles system design. Analysis: A fundamental data analysis skill. Review: A skill for reviewing deliverables. Unknown: Skill is unknown.
SwitchExpression.cs
using System;
// Base class for workers.
class Worker {
public string Name { get; set; }
public Worker(string name) { Name = name; }
}
// Subclass for skilled workers.
class SkilledWorker : Worker {
public int Score { get; set; }
public SkilledWorker(string name, int score) : base(name) {
Score = score;
}
}
// Class representing a task item.
class TaskItem : Worker {
public string Level { get; set; }
public TaskItem(string name, string level) : base(name) {
Level = level;
}
}
class SwitchExpression {
static void Main() {
// Classifies entities as workers, tasks, or other types.
object[] entities = {
new SkilledWorker("member_2", 1200),
new SkilledWorker("member_1", 8500),
new TaskItem("item_b", "S"),
new TaskItem("item_d", "S"),
"item_c (unclassified)"
};
foreach (object entity in entities) {
string status = entity switch {
// SkilledWorker with score above 8000 is a Level S candidate.
SkilledWorker s when s.Score > 8000
=> s.Name + " is a Level S candidate (score: " + s.Score + ").",
// Any other SkilledWorker.
SkilledWorker s
=> s.Name + " is a worker (score: " + s.Score + ").",
// Level S task item.
TaskItem c when c.Level == "S"
=> c.Name + " is a Level S task.",
// Any other task item.
TaskItem c
=> c.Name + " is a " + c.Level + " task.",
// String or any other unrecognized type.
string s
=> s + " (unknown entity)",
// Fallback for all remaining types.
_ => "Unknown entity."
};
Console.WriteLine(status);
}
Console.WriteLine();
string[] levels = { "S", "A", "B", "C", "D" };
foreach (string level in levels) {
int allowance = level switch {
"S" => 500000,
"A" => 200000,
"B" => 100000,
"C" => 50000,
_ => 20000 // Default value for D and below.
};
Console.WriteLine("Level " + level + " monthly allowance: " + allowance + " yen");
}
}
}
This produces the following output:
dotnet script SwitchExpression.cs member_2 is a worker (score: 1200). member_1 is a Level S candidate (score: 8500). item_b is a Level S task. item_d is a Level S task. item_c (unclassified) (unknown entity) Level S monthly allowance: 500000 yen Level A monthly allowance: 200000 yen Level B monthly allowance: 100000 yen Level C monthly allowance: 50000 yen Level D monthly allowance: 20000 yen
Common Mistakes
Forgetting break and getting a compile error
In C#, omitting break (or return / throw / goto case) at the end of a case causes a compile error. Unlike C or Java, implicit fall-through is not allowed.
switch (value) {
case 1:
Console.WriteLine("one");
// No break — compile error CS0163.
case 2:
Console.WriteLine("two");
break;
}
Omitting _ (wildcard) in a switch expression
If a switch expression does not cover all possible cases, the compiler issues a warning. For non-enum types, always include _ (wildcard) to handle unexpected values.
string label = value switch {
1 => "one",
2 => "two",
_ => "other" // Do not omit this.
};
Overview
The switch statement in C# is the traditional multi-branch construct. Each case specifies a value to match, and every branch must end with break, return, or throw. In C#, implicit fall-through — omitting break to let execution continue into the next case — is a compile error. To intentionally transfer control to another case, write goto case value explicitly.
The switch expression, introduced in C# 8, provides a compact way to select and return a value from multiple options. Each arm is separated by an arrow (=>), and the wildcard (_) specifies the default value. Adding a when guard to an arm lets you combine type and value conditions in a single expression. The compiler checks that all possible cases are handled, so omissions are caught early.
For type-based pattern matching, see also is / as / Pattern Matching. For simple true/false branching, see if / else.
If you find any errors or copyright issues, please contact us.