Skip to Content
Course content

11: Control Flow: Switch Statements and Switch Expressions

Click on the "Edit" button in the top corner of the screen to edit your slide content.

A few years ago, I was reviewing a pull request for a junior developer who had built a notification dispatcher. He had this monstrous if-else if chain checking for NotificationType. Every time the team added a new channel—Slack, SMS, Email, PagerDuty—the block grew. By the time he reached the fifth condition, the code was indented so far to the right that he was practically writing in the gutter of the IDE. It was an indentation nightmare and, more importantly, a maintenance landmine. I remember telling him, "You're treating C# like it's 1995. Let's clean this up."

Taming the Logic with Switch Statements

When you're comparing a single variable against a long list of possible constant values, a switch statement is your best friend. It's cleaner than a chain of if statements and tells anyone reading your code exactly what the intent is: "I have one value, and I need to do something different depending on what that value is."

Here is how we would have refactored that notification dispatcher. Instead of checking the type over and over, we jump straight to the matching case:

string notificationType = "Email";

switch (notificationType)
{
    case "Email":
        Console.WriteLine("Sending SMTP request...");
        break;
    case "SMS":
        Console.WriteLine("Connecting to Twilio API...");
        break;
    case "Slack":
        Console.WriteLine("Posting to Webhook...");
        break;
    default:
        Console.WriteLine("Unknown notification type. Logging error.");
        break;
}

One thing to keep in mind: C# requires that break (or return/throw) at the end of every case. You can't "fall through" from one case to another like you can in some older languages. If you want two cases to execute the same code, you just stack them on top of each other without a break in between.

The Power of Switch Expressions

Now, if you're using a modern version of C#, you'll find that we rarely use the classic switch statement when we just want to assign a value to a variable. That's where switch expressions come in. Introduced in C# 8.0, these are essentially a "compressed" version of the switch statement that returns a value directly.

I personally prefer these because they remove all the boilerplate—no case keywords, no break statements, and no curly brace clutter. Imagine you're writing a system to determine the access level of a user based on their role:

string userRole = "Editor";

int accessLevel = userRole switch
{
    "Admin"  => 10,
    "Editor" => 5,
    "Viewer" => 1,
    _        => 0 // The underscore is the 'discard' pattern, acting as the default
};

Notice the _ symbol. In a switch expression, that's your default case. It's mandatory if the compiler can't prove that you've covered every single possible value of the input type. If you forget it, C# will throw a warning (or an exception at runtime) because it doesn't want you accidentally leaving a value unhandled.

Pattern Matching and Logic Guards

The real magic happens when you stop switching on simple strings or ints and start using patterns. You can actually put logic inside your switch arms using the when keyword. This allows you to handle complex conditions while keeping the structural beauty of the switch.

Let's say you're calculating shipping costs based on a package's weight and its destination. You can mix constant matches with logical guards:

decimal CalculateShipping(double weight, string zone) => weight switch
{
    < 1.0 => 5.00m,
    < 5.0 when zone == "Domestic" => 10.00m,
    < 5.0 when zone == "International" => 25.00m,
    _ => 50.00m
};

I love this approach because it reads almost like a business requirement document. "If it's under 1kg, it's $5. If it's under 5kg and domestic, it's $10." It's readable, concise, and far less prone to the "off-by-one" errors I've seen in nested if blocks.




📋 Practical Task

Exercise: Elemental Damage Multiplier

You are building a combat system for an RPG. You need to create a method that calculates a damage multiplier based on the attackerElement and the defenderElement.

Requirements:

  • Use a switch expression to determine the multiplier.
  • If the attacker is "Fire" and the defender is "Grass", the multiplier should be 2.0 (Super Effective).
  • If the attacker is "Fire" and the defender is "Water", the multiplier should be 0.5 (Not Very Effective).
  • If the attacker is "Water" and the defender is "Fire", the multiplier should be 2.0.
  • If the attacker is "Water" and the defender is "Grass", the multiplier should be 0.5.
  • For any other combination, the multiplier should be 1.0 (Neutral).

Hint: Since you are checking two different variables, you can switch on a Tuple. For example: (attackerElement, defenderElement) switch { ... }

Rating
0 0

There are no comments for now.

to be the first to leave a comment.