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

  1. The classic switch statement
  2. case, default, and the importance of break
  3. Multiple values for the same case
  4. switch vs if/else if/else
  5. A look ahead: switch expressions and pattern matching
  6. Full application: classifying a book by category

  1. The classic switch statement

A 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 type string, any integer numeric type, char, bool, or an enum (which will be covered in detail in later modules).
  • Each case value: defines a possible match. If expression == value, the corresponding code block runs.
  • default: runs if none of the preceding case labels match. It's equivalent to the final else of an if/else if/else chain, and although it's technically optional, it's recommended to always include it to cover unexpected cases.

  1. case, default, and the importance of break

Unlike 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

  1. Multiple values for the same case

When 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".

  1. 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.

  1. 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.

  1. 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 a case with code that doesn't end in break (or another exit statement like return). 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 case value: two case labels 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-out default ("category not recognized") avoids silent, unexpected behavior.
  • Using switch for numeric ranges (pages > 100 && pages < 300): the classic switch compares exact equality, not ranges; for that, use if/else if/else.
  • Mixing value types in the case labels: all case values must be compatible with the type of the switch expression (if it compares a string, all the case labels must be string literals).

Exercises

  1. Declare int dayOfWeek with a value from 1 to 7. Write a switch that prints to the console the name of the corresponding day (1 -> "Monday", ..., 7 -> "Sunday"), and an "Invalid day" message in the default.

  2. Declare string format with one of these values: "Hardcover", "Paperback", "Digital", "Audiobook". Using stacked case labels, group "Hardcover" and "Paperback" under the message "Physical format", and group "Digital" and "Audiobook" under the message "Electronic format".

  3. Given the array string[] categories = { "Poetry", "Horror", "Fiction" };, iterate over the array with foreach and, for each category, use a switch to 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.

© Copyright 2026. All rights reserved