Skip to main content

    Lesson 4 • Beginner Track

    Control Flow

    By the end of this lesson you'll be able to make your programs decide — branching with if/else, picking from many options with switch, and matching ranges and types with pattern matching. This is what turns a fixed list of instructions into a program that reacts.

    What You'll Learn

    • Write if, else-if, and else statements to make decisions in your code
    • Use the ternary operator for concise one-line conditional choices
    • Build switch statements for handling many specific cases
    • Use modern switch expressions with pattern matching (C# 8+)
    • Apply relational patterns (< 5, >= 18) and combinators (and, or)
    • Classify values by type using pattern matching

    💡 Real-World Analogy

    Control flow is like a railway switching station. A train (your program) arrives at a junction and the switch operator (your condition) sends it down one of several tracks. An if-else is a simple fork: left or right. A switch is a complex junction with many possible tracks. Pattern matching is the automated system that reads the cargo's type and weight to route it to exactly the right platform. Without control flow, the train can only ever roll straight ahead.

    📊 Control Flow Quick Reference

    StructureUse WhenExample
    if / else2-3 conditions, boolean logicAge check, validation
    ternary ? :Simple true/false choicecond ? "A" : "B"
    switch statementMany discrete valuesDay of week, menu options
    switch expressionReturn a value from patternsPrice tiers, classifications
    pattern matchingType checks, range checksObject classification

    1. If, Else-If, and Else

    The if statement runs a block of code only when its condition is true. Add else if for more checks and a final else as a catch-all. The key rule: the chain is read top to bottom and the first true branch wins — the rest are skipped. For a simple two-way choice, the ternary operator (condition ? a : b) does it in one line. Read this worked example and run it first.

    Worked example: if-else, ternary & logical operators

    Read every comment, run it, and check which branch fires.

    Try it Yourself »
    C#
    using System;
    
    class Program
    {
        static void Main()
        {
            int score = 85;
    
            // An if-else if-else chain is checked TOP to BOTTOM.
            // The FIRST condition that is true wins; the rest are skipped.
            if (score >= 90)
            {
                Console.WriteLine("Grade: A — Excellent!");
            }
            else if (score >= 80)
            {
                Console.WriteLine("Grade: B — Great job!");   // score is 85 -> THIS runs
            }
            else if (score >= 70)
            {
        
    ...

    Your turn. The classifier below is almost complete — fill in the four blanks marked ___ using the hints. Remember branches are checked top to bottom, so the conditions must go from smallest range upward.

    🎯 Your turn: complete the age classifier

    Fill in the ___ blanks, then check your output against the expected line.

    Try it Yourself »
    C#
    using System;
    
    class Program
    {
        static void Main()
        {
            // 🎯 YOUR TURN — finish the age-bracket classifier.
            // Replace each ___ then press "Try it Yourself".
    
            int age = 40;
    
            // Branches run TOP to BOTTOM, so order from SMALLEST upward.
            if (age ___ 13)                 // 👉 use  <  so under-13s match first
            {
                Console.WriteLine("Child");
            }
            else if (age < ___)             // 👉 use 20: anyone 13..19 is a teen
            {
    
    ...

    2. Switch Statements & Expressions

    Reach for switch when one value can take many specific forms. The traditional switch statement lists each case and needs a break to end it. The modern C# 8+ switch expression is tidier — it returns a value with the => arrow, needs no break, and supports relational patterns like >= 3 and <= 5. Use _ (the discard) as the catch-all.

    Worked example: switch statement vs switch expression

    Compare the traditional switch with the modern switch expression.

    Try it Yourself »
    C#
    using System;
    
    class Program
    {
        static void Main()
        {
            // Traditional switch STATEMENT — every case needs a break.
            int day = 3;
            switch (day)
            {
                case 1: Console.WriteLine("Monday"); break;
                case 2: Console.WriteLine("Tuesday"); break;
                case 3: Console.WriteLine("Wednesday"); break;   // day is 3 -> this prints
                case 4: Console.WriteLine("Thursday"); break;
                case 5: Console.WriteLine("Friday"); break;
         
    ...

    Now you try. Complete the traffic-light switch expression below by filling in the two blanks — one quoted action and the discard pattern that catches anything unexpected.

    🎯 Your turn: complete the traffic-light switch

    Map each colour to an action, then run it to check the output.

    Try it Yourself »
    C#
    using System;
    
    class Program
    {
        static void Main()
        {
            // 🎯 YOUR TURN — map a traffic-light colour to a driver action.
            // Fill in the blanks in this switch EXPRESSION.
    
            string light = "amber";
    
            string action = light switch
            {
                "red"   => "___",            // 👉 text in quotes, e.g. Stop
                "amber" => "Slow down",      // light is "amber" -> this arm is chosen
                "green" => "Go",
                ___     => "Unknown signal"  // 
    ...

    3. Pattern Matching

    Pattern matching is one of C#'s most powerful features. A switch expression can match on value ranges (relational patterns like < 5), on types (type patterns like obj is string s), and you can attach an extra when guard for fine-grained checks. It replaces tangled if-else chains with clean, declarative code that the compiler can even check for completeness.

    Worked example: relational & type patterns

    Use range patterns to price tickets and type patterns to classify values.

    Try it Yourself »
    C#
    using System;
    
    class Program
    {
        // A switch expression as a method body — maps an age to a ticket price.
        static string GetTicketPrice(int age) => age switch
        {
            < 5            => "Free",         // ages 0-4
            >= 5 and < 13  => "£5 (Child)",   // ages 5-12
            >= 13 and < 18 => "£8 (Teen)",    // ages 13-17
            >= 18 and < 65 => "£12 (Adult)",  // ages 18-64
            >= 65          => "£6 (Senior)",  // ages 65+
            _              => "Unknown"       // negative a
    ...

    Putting It Together: a Cinema Entry Desk

    Here's a small but real program that uses everything from this lesson at once — an if/else if chain to choose an age band, a switch expression to map that band to a price, a ternary for the VIP surcharge, and || to decide admission. Read it line by line; you understand every part now.

    Worked example: cinema entry desk

    Change the age, ticket type, and guardian flag and watch each decision update.

    Try it Yourself »
    C#
    using System;
    
    class Program
    {
        static void Main()
        {
            // === Cinema entry desk — combines this whole lesson ===
            int age = 16;
            string ticketType = "standard";   // "standard" or "vip"
            bool hasGuardian = true;
    
            // 1) if / else-if / else picks the age band (first true wins, top-down).
            string band;
            if (age < 13)            band = "Child";    // not this one
            else if (age < 18)       band = "Teen";     // age 16 -> THIS one
            
    ...

    This is the shape of nearly all real logic: a few branches pick a category, a mapping turns that category into a value, and a final condition decides the outcome.

    Common Errors (and the fix)

    • Wrong order of else-if (unreachable branch): putting if (score >= 60) before if (score >= 90) means an A grade can never fire — 90 already matched 60. Order from the most specific (smallest range) upward.
    • "CS0163 / CS8070: control cannot fall through" — missing break: every non-empty case in a switch statement must end with break (or return). C# won't let cases fall through silently like JavaScript does.
    • "CS0029: Cannot implicitly convert 'int' to 'bool'" — = vs ==: if (x = 5) assigns and is not a condition. Use == to compare: if (x == 5).
    • SwitchExpressionException at runtime: a switch expression with no _ arm throws if no pattern matches the input. Always add a _ => ... catch-all.
    • Empty if block: if (condition) {} compiles but does nothing — usually a stray semicolon (if (x > 0);) ended the statement early. Remove it.

    Pro Tips

    • 💡 Prefer switch expressions over if-else chains when mapping an input to an output — they're cleaner and the compiler warns if you miss a case.
    • 💡 Always include a _ (discard) or default so unexpected values can't slip through or crash at runtime.
    • 💡 Combine type-check and cast with is: if (obj is string s && s.Length > 5) tests the type, casts to s, and reads it in one step.
    • 💡 Avoid deeply nested ifs: use early returns or guard clauses to flatten logic and keep it readable.

    Frequently Asked Questions

    Q: When should I use a switch instead of if/else if?

    Use switch when you're checking one value against many specific options (a day number, a status string, an age band). Use if/else if when conditions are unrelated or combine several variables with && and ||.

    Q: What's the difference between a switch statement and a switch expression?

    A statement does something in each case (and needs break). An expression returns a value using the => arrow and is assigned to a variable: string s = day switch { ... };. The expression form is the modern default for mapping input to output.

    Q: Do I always need an else or a _ case?

    Not for an if — it can run nothing if no branch matches. But a switch expression should always have a _ arm, otherwise it throws SwitchExpressionException when nothing matches.

    Q: Why did my code assign instead of compare?

    You wrote = (assignment) where you meant == (equality). In C# a condition must be a bool, so if (x = 5) is a compile error — a helpful reminder to use ==.

    📋 Quick Reference

    TaskCodeNotes
    Branchif (x > 0) { ... } else { ... }First true block runs
    One-line choicevar s = ok ? "Y" : "N";Ternary operator
    Multi-caseswitch (d) { case 1: ...; break; }Needs break
    Return a valuevar n = d switch { 1 => "Mon", _ => "?" };No break; needs _
    Range pattern>= 18 and < 65 => "Adult"Relational + and/or
    Type patternobj is string sTest type + cast

    Mini-Challenge: FizzBuzz

    No blanks this time — just a brief and an outline. FizzBuzz is the classic control-flow exercise (and a real interview question): loop 1 to 15, and for each number print "Fizz", "Buzz", "FizzBuzz", or the number itself. The trick is checking the "both" case first. Build it, run it, and match the expected output in the comments.

    🎯 Mini-Challenge: build FizzBuzz (1..15)

    Write the if-else chain yourself and print one result per line.

    Try it Yourself »
    C#
    using System;
    
    class Program
    {
        static void Main()
        {
            // 🎯 MINI-CHALLENGE: FizzBuzz for 1..15
            // 1. Loop the numbers 1 to 15 with:  for (int i = 1; i <= 15; i++)
            // 2. For each number, use if / else if / else to decide what to print:
            //      - divisible by BOTH 3 and 5  -> "FizzBuzz"   (test:  i % 15 == 0)
            //      - divisible by 3 only        -> "Fizz"       (test:  i % 3 == 0)
            //      - divisible by 5 only        -> "Buzz"       (test:  i %
    ...

    🎉 Lesson Complete

    • if / else if / else branches on boolean conditions — first true branch wins
    • ✅ Ternary ? : for concise single-line two-way choices
    • switch statements handle many specific values with case and break
    • ✅ Switch expressions (C# 8+) return values with => and need a _ catch-all
    • ✅ Relational patterns: < 5, >= 18 and < 65 — match ranges in a switch
    • ✅ Type patterns: obj is string s — test the type and cast in one step
    • Next lesson: Loops — for, while, do-while, and foreach

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service