In the previous lesson you saw how to repeat actions with loops; before that, you learned to
make decisions with if/else if/else. However, when the same variable must be compared
against many possible values — for example, classifying a BiblioTech book by its category:
"Fiction", "Non-fiction", "Poetry", "Children's", "Science" — chaining else if over and over
becomes repetitive and hard to read. The switch statement solves exactly that case: it
compares an expression against a list of possible values and runs the block that matches, with
clearer, more orderly syntax.
Content
- The classic
switchstatement case,default, and the importance ofbreak- Multiple values for the same
case switchvsif/else if/else- A look ahead: switch expressions and pattern matching
- Full application: classifying a book by category
- The classic
switch statement
switch statementA switch evaluates an expression once and compares its result against a series of constant
values, each defined in a case label.
string category = "Fiction";
switch (category)
{
case "Fiction":
Console.WriteLine("Fiction section - Floor 1");
break;
case "Non-fiction":
Console.WriteLine("Non-fiction section - Floor 2");
break;
case "Poetry":
Console.WriteLine("Poetry section - Floor 1");
break;
default:
Console.WriteLine("Category not recognized - check with the librarian");
break;
}Structure of the statement:
switch (expression): the expression is evaluated exactly once; it can be of typestring, any integer numeric type,char,bool, or anenum(which will be covered in detail in later modules).- Each
case value:defines a possible match. Ifexpression == value, the corresponding code block runs. default:runs if none of the precedingcaselabels match. It's equivalent to the finalelseof anif/else if/elsechain, and although it's technically optional, it's recommended to always include it to cover unexpected cases.
case, default, and the importance of break
case, default, and the importance of breakUnlike other languages, in C# every case block must end explicitly — normally with
break — before moving on to the next one. If a case doesn't contain any statement that
ends the block (break, return, throw, or continuing with goto case), the compiler
raises an error: C# doesn't allow implicit "fall-through" (accidentally dropping from one
case into the next), which does exist in languages like C or Java.
For everyday use, it's enough to remember the simple rule: every case must close with
break (or with return if the switch is inside a method that must return a value).
string category = "Comic";
switch (category)
{
case "Fiction":
Console.WriteLine("Fiction");
break;
case "Comic":
Console.WriteLine("Comics and graphic novels");
break; // mandatory: without this break, the code won't compile
default:
Console.WriteLine("Unclassified");
break;
}| Element | Mandatory? | Purpose |
|---|---|---|
switch (expr) |
Yes | Opens the structure and defines what will be compared |
case value: |
At least one (or default) |
Defines a possible matching value |
break; |
Yes (for every case with code) |
Ends the block and exits the switch |
default: |
Recommended, not mandatory | Covers any value not handled by the case labels |
- Multiple values for the same
case
caseWhen several distinct values should trigger exactly the same action, you can "stack" several
case labels one after another, with no code between them, before the shared block:
string category = "Children's";
switch (category)
{
case "Children's":
case "Young Adult":
Console.WriteLine("Family section - Ground floor");
break;
case "Fiction":
case "Science Fiction":
case "Fantasy":
Console.WriteLine("Fiction section - Floor 1");
break;
case "Non-fiction":
case "History":
case "Science":
Console.WriteLine("Non-fiction section - Floor 2");
break;
default:
Console.WriteLine("Category not recognized");
break;
}Here, both "Children's" and "Young Adult" run the same block, because C# allows "stacking"
case labels with no break in between: only the last case in the group carries the code
and the break. This is different from the forbidden fall-through: stacking empty labels is
allowed because there's no code between them that could be accidentally "skipped".
switch vs if/else if/else
switch vs if/else if/else| Aspect | switch |
if/else if/else |
|---|---|---|
| Comparisons | Exact equality against constant values | Any boolean condition, including ranges |
| Readability with many values | High: each case is a clear single line | Low: the same variable is repeated many times |
Ranges (pages > 100 && pages < 300) |
Not directly (requires advanced tricks) | Yes, naturally |
| Supported types | string, integers, char, bool, enum, patterns |
Any boolean expression |
Practical rule: if you're comparing the same variable against a fixed list of concrete
values (categories, codes, menu options), use switch. If you need to evaluate ranges,
combinations of several variables, or more elaborate conditions, use if/else if/else as
in the first lesson of this module.
- A look ahead: switch expressions and pattern matching
The classic switch you've seen in this lesson has existed since the earliest versions of
C#. More recent versions of the language introduce so-called switch expressions (a more
compact way of writing a switch that returns a value directly, without case/break)
and advanced pattern matching (comparing not just exact values, but also types, ranges,
or entire data structures). As a preview, here's a switch expression equivalent to one of the
previous examples:
string category = "Fiction";
string section = category switch
{
"Fiction" => "Fiction - Floor 1",
"Non-fiction" => "Non-fiction - Floor 2",
"Poetry" => "Poetry - Floor 1",
_ => "Category not recognized"
};
Console.WriteLine(section);For now, it's enough to recognize this syntax if you see it in someone else's code; you don't
need to master it yet. Module 4 (Advanced C# Concepts) devotes a full lesson to Pattern
Matching and Modern Features, where you'll go deeper into switch expressions, and type,
property, and range patterns. For now, master the classic switch well: it's the foundation
on which all those modern variants are understood.
- Full application: classifying a book by category
Let's build a small BiblioTechConsole utility that, given a book's category, determines which floor it's physically located on and displays a descriptive message.
string[] bookCategories = { "Fiction", "Comic", "Non-fiction", "Children's", "Manga", "Unknown" };
foreach (string category in bookCategories)
{
string location;
switch (category)
{
case "Fiction":
case "Science Fiction":
case "Fantasy":
location = "Floor 1 - Fiction";
break;
case "Non-fiction":
case "History":
location = "Floor 2 - Non-fiction";
break;
case "Children's":
case "Young Adult":
location = "Ground floor - Family section";
break;
case "Comic":
case "Manga":
location = "Floor 1 - Comics and graphic novels";
break;
default:
location = "No location assigned - check with the librarian";
break;
}
Console.WriteLine($"{category} -> {location}");
}Expected output:
Fiction -> Floor 1 - Fiction Comic -> Floor 1 - Comics and graphic novels Non-fiction -> Floor 2 - Non-fiction Children's -> Ground floor - Family section Manga -> Floor 1 - Comics and graphic novels Unknown -> No location assigned - check with the librarian
Notice how the switch keeps the code far more organized than a long chain of else if
statements always comparing the same category variable.
Common Mistakes and Tips
- Forgetting the
break: C# won't compile acasewith code that doesn't end inbreak(or another exit statement likereturn). The compiler will warn you with a clear error; don't think of it as a quirk of the language, but as protection against the accidental fall-through bug that's so common in other languages. - Duplicating a
casevalue: twocaselabels with the same value won't compile. Check that each value appears only once. - Forgetting the
default: although it's not mandatory, omitting it can leave situations uncovered. In BiblioTechConsole, a well-thought-outdefault("category not recognized") avoids silent, unexpected behavior. - Using
switchfor numeric ranges (pages > 100 && pages < 300): the classicswitchcompares exact equality, not ranges; for that, useif/else if/else. - Mixing value types in the
caselabels: allcasevalues must be compatible with the type of theswitchexpression (if it compares astring, all thecaselabels must be string literals).
Exercises
-
Declare
int dayOfWeekwith a value from 1 to 7. Write aswitchthat prints to the console the name of the corresponding day (1->"Monday", ...,7->"Sunday"), and an"Invalid day"message in thedefault. -
Declare
string formatwith one of these values:"Hardcover","Paperback","Digital","Audiobook". Using stackedcaselabels, group"Hardcover"and"Paperback"under the message"Physical format", and group"Digital"and"Audiobook"under the message"Electronic format". -
Given the array
string[] categories = { "Poetry", "Horror", "Fiction" };, iterate over the array withforeachand, for each category, use aswitchto print"Floor 1"if it's"Fiction"or"Poetry", and"Unclassified"in any other case (including"Horror", which isn't explicitly handled).
Solutions
int dayOfWeek = 3;
switch (dayOfWeek)
{
case 1:
Console.WriteLine("Monday");
break;
case 2:
Console.WriteLine("Tuesday");
break;
case 3:
Console.WriteLine("Wednesday");
break;
case 4:
Console.WriteLine("Thursday");
break;
case 5:
Console.WriteLine("Friday");
break;
case 6:
Console.WriteLine("Saturday");
break;
case 7:
Console.WriteLine("Sunday");
break;
default:
Console.WriteLine("Invalid day");
break;
}
With dayOfWeek = 3, the result printed is "Wednesday".
string format = "Digital";
switch (format)
{
case "Hardcover":
case "Paperback":
Console.WriteLine("Physical format");
break;
case "Digital":
case "Audiobook":
Console.WriteLine("Electronic format");
break;
default:
Console.WriteLine("Format not recognized");
break;
}
With format = "Digital", the result printed is "Electronic format".
string[] categories = { "Poetry", "Horror", "Fiction" };
foreach (string category in categories)
{
switch (category)
{
case "Fiction":
case "Poetry":
Console.WriteLine("Floor 1");
break;
default:
Console.WriteLine("Unclassified");
break;
}
}
The result printed is: "Floor 1" (for "Poetry"), "Unclassified" (for "Horror",
which falls into the default since it's not handled) and "Floor 1" (for "Fiction").
Conclusion
In this lesson you've learned to use switch to compare the same variable against a list of
possible values in a clear and orderly way, the importance of break in every case, how to
group several values under the same action, and when to choose switch over
if/else if/else. You've also had a brief preview of modern switch expressions and pattern
matching, which you'll revisit in depth in Module 4.
So far, in every example in this module, the code has assumed data arrives in the correct
format. But in a real program, any operation — converting text to a number, accessing a
position in an array, lending a book that doesn't exist — can fail. In the last lesson of this
module, Exception Handling, you'll learn to anticipate and manage those errors in a
controlled way with try/catch/finally, so that BiblioTechConsole doesn't come to an
abrupt stop when it encounters unexpected data.
C# Programming Course
Module 1: Introduction to C#
- Introduction to C#
- Setting Up the Development Environment
- Hello World Program
- Basic Syntax and Structure
- Variables and Data Types
- Arrays and Strings
Module 2: Control Structures
Module 3: Object-Oriented Programming
- Classes and Objects
- Methods
- Constructors and Destructors
- Inheritance
- Polymorphism
- Encapsulation
- Abstraction
- Structs and Records: Value Types and Reference Types
Module 4: Advanced C# Concepts
- Interfaces
- Delegates and Events
- Pattern Matching and Modern C# Features
- Generics
- Collections
- LINQ (Language Integrated Query)
- Asynchronous Programming
Module 5: Working with Data
- File I/O
- Serialization
- Database Connectivity
- Entity Framework
- Working with JSON and Consuming REST APIs
Module 6: Advanced Topics
- Reflection
- Attributes
- Dynamic Programming
- Memory Management and Garbage Collection
- Multithreading and Parallel Programming
Module 7: Building Applications
Module 8: Best Practices and Design Patterns
- Coding Standards and Best Practices
- Design Patterns
- Dependency Injection and Inversion of Control
- Unit Testing
- Code Review and Refactoring
