Programs need to make decisions. Should the discount apply? Is the password long enough? Which message should a user see for their order status? Conditional statements run different code depending on whether a condition is true or false.
C# gives you several tools for this. if, else if and else handle most decisions. The ternary operator ? : picks between two values in a single expression. switch chooses between many possible values, and modern C#'s switch expressions do the same in a compact form that returns a value.
C# also supports patterns, which let a condition check ranges (< 18), combinations (>= 13 and <= 19) and types, all in readable syntax. In this lesson you'll use each of these, learn when one fits better than another, and write conditions that are easy to read and hard to get wrong.
if, else if and else
int score = 72;
if (score >= 90)
{
Console.WriteLine("Grade A");
}
else if (score >= 70)
{
Console.WriteLine("Grade B");
}
else
{
Console.WriteLine("Keep practising");
}- The condition in brackets must be a
bool. - C# checks each condition from top to bottom and runs only the first block whose condition is true.
- Braces are optional for one-line bodies, but using them always prevents mistakes when lines are added later.
The ternary operator and guard clauses
The conditional operator chooses between two values: condition ? valueIfTrue : valueIfFalse.
string label = stock > 0 ? "In stock" : "Sold out";In methods, a guard clause handles invalid cases early and returns, so the main logic isn't buried in nested if blocks:
if (basket.Count == 0) return "Your basket is empty";
if (!user.IsVerified) return "Please verify your email";
// main logic here, without nestingswitch statements and switch expressions
A switch statement compares one value against many cases:
switch (day)
{
case "Sat":
case "Sun":
Console.WriteLine("Weekend");
break;
default:
Console.WriteLine("Weekday");
break;
}Each section ends with break, and C# doesn't let execution fall through into the next section.
A switch expression returns a value and is often clearer:
string message = status switch
{
"paid" => "Thanks for your order",
"shipped" => "On its way",
_ => "Processing"
};_ is the discard pattern that matches anything, like default.
Patterns in conditions
Patterns make range and combination checks readable:
string group = age switch
{
< 13 => "Child",
>= 13 and <= 19 => "Teen",
>= 65 => "Senior",
_ => "Adult"
};
if (input is not null and not "") { }
if (code is "GB" or "IE") { }A when clause adds an extra condition to a case: case > 100 when isMember:. Patterns also work with types and object properties, which you'll meet in the pattern matching lesson.
Switching on two values at once
Sometimes a decision depends on more than one value. Instead of nesting if statements, put the values in a tuple and switch on them together:
static string Discount(bool isMember, decimal total) => (isMember, total) switch
{
(true, >= 50m) => "20% off",
(true, _) => "10% off",
(false, >= 100m) => "5% off",
_ => "No discount"
};
Console.WriteLine(Discount(true, 60m)); // 20% off
Console.WriteLine(Discount(false, 120m)); // 5% offEach arm reads like a row in a table of rules, which makes it easy to compare with a written specification. _ inside the brackets means "any value in this position", so (true, _) matches every member whose total didn't reach the first arm.
When no switch arm matches
A switch statement without a default section simply does nothing when no case matches. A switch expression is different, because it must produce a value. If you leave a gap, the compiler warns you with CS8509, "the switch expression does not handle all possible values", and even names an example value it doesn't cover:
static string Size(int n) => n switch
{
< 10 => "small",
>= 10 and < 100 => "medium"
}; // warning CS8509: 100 is not coveredIf you ignore the warning and call Size(500), the program throws a SwitchExpressionException at run time. Fix it by adding a final _ => arm, either with a sensible value or with throw new ArgumentOutOfRangeException(nameof(n)) when the value really should never happen. Treat this warning as an error: it points straight at a bug waiting to happen.
C# Control Flow Syntax
Conditions
if (x > 0) { } else if (x < 0) { } else { }
string s = ok ? "yes" : "no";
switch (n)
{
case 1: Console.WriteLine("one"); break;
case 2 or 3: Console.WriteLine("few"); break;
default: Console.WriteLine("many"); break;
}
string size = cm switch { < 150 => "S", < 180 => "M", _ => "L" };
if (age is >= 18 and < 65) { }
if (name is null or "") { }C# Control Flow Summary
- if, else if and else run the first block whose condition is true.
- condition ? a : b picks between two values in one expression.
- Guard clauses return early and keep code flat.
- switch statements need break; switch expressions return a value with =>.
- Patterns such as < 18, and, or, not and _ make conditions readable.
C# Control Flow Examples
Each example shows the code, the output it produces and what each part does.
Shipping costs with if and else
decimal ShippingCost(decimal total, bool isMember)
{
if (total <= 0)
{
return 0;
}
if (isMember || total >= 50)
{
return 0;
}
else if (total >= 20)
{
return 2.99m;
}
else
{
return 4.99m;
}
}
Console.WriteLine(ShippingCost(65, false));
Console.WriteLine(ShippingCost(30, false));
Console.WriteLine(ShippingCost(12, false));
Console.WriteLine(ShippingCost(12, true));0
2.99
4.99
0Line-by-line explanation
- Lines 3 to 6A guard clause handles an empty basket first.
- Line 7Members and large orders pay nothing for delivery.
- Line 11else if is only checked when the first condition was false.
- Lines 21 to 24Each call takes a different path through the conditions.
A switch expression with patterns
string Describe(int temperature) => temperature switch
{
< 0 => "Freezing",
>= 0 and < 12 => "Cold",
>= 12 and < 22 => "Mild",
>= 22 and < 30 => "Warm",
_ => "Hot"
};
int[] readings = { -4, 8, 18, 25, 33 };
foreach (int t in readings)
{
Console.WriteLine($"{t}°C: {Describe(t)}");
}
string role = "editor";
bool canPublish = role is "admin" or "editor";
Console.WriteLine(canPublish ? "Can publish" : "Read only");-4°C: Freezing
8°C: Cold
18°C: Mild
25°C: Warm
33°C: Hot
Can publishLine-by-line explanation
- Line 1An expression-bodied method returns the result of the switch expression.
- Lines 3 to 6Relational patterns check ranges without repeating the variable name.
- Line 7The discard _ catches everything else.
- Line 17An or pattern compares against two values.
- Line 18The ternary operator chooses which message to print.
A switch statement for menu choices
string[] choices = { "1", "2", "3", "q", "x" };
foreach (string choice in choices)
{
switch (choice)
{
case "1":
Console.WriteLine("Showing orders");
break;
case "2":
case "3":
Console.WriteLine("Showing reports");
break;
case "q":
Console.WriteLine("Goodbye");
break;
default:
Console.WriteLine($"Unknown option '{choice}'");
break;
}
}Showing orders
Showing reports
Showing reports
Goodbye
Unknown option 'x'Line-by-line explanation
- Lines 7 to 9Each case section ends with break.
- Lines 10 to 11Stacking labels lets two values share one block.
- Lines 17 to 19default runs when no case matches.
Common C# Control Flow Mistakes
Using = in a condition
if (isAdmin = true) { } // assigns true, so the block always runs (with a warning)if (isAdmin) { }General conditions first
if (score >= 50) grade = "Pass";
else if (score >= 80) grade = "Merit"; // never reachedif (score >= 80) grade = "Merit";
else if (score >= 50) grade = "Pass";Forgetting break in a switch statement
case "a":
Console.WriteLine("A");
case "b": // error CS0163: control cannot fall through from one case label to another
Console.WriteLine("B");
break;case "a":
Console.WriteLine("A");
break;
case "b":
Console.WriteLine("B");
break;C# Control Flow in Real Projects
Decisions in real applications
Web APIs return different responses depending on validation results with guard clauses at the top of each endpoint. Pricing engines use switch expressions to map customer tiers and order sizes to discounts. Games pick enemy behaviour from a switch over states. Status labels on screens are often a single switch expression from an enum value to text.
C# Control Flow FAQ
What is the difference between a switch statement and a switch expression?
A switch statement runs blocks of code and uses case, break and default. A switch expression, written value switch { pattern => result, ... }, produces a single value that you can assign or return, and it uses _ instead of default. Use the expression when every branch simply chooses a value, and the statement when branches need to run several lines.
Can a C# switch case fall through to the next case?
Not if the case contains code: every non-empty section must end with break, return, throw or goto case, otherwise you get error CS0163. Empty case labels stacked together, such as case "Sat": case "Sun":, are allowed and share one block of code.
Can I use a switch with strings in C#?
Yes. Both switch statements and switch expressions match strings exactly, including case, so "Paid" won't match "paid". Normalise the input first with ToLowerInvariant() or Trim() if users might type it differently.
How do I check if a number is between two values in C#?
Write x >= 1 && x <= 10, or use a relational pattern: x is >= 1 and <= 10. The pattern form is shorter and also works inside switch expressions, for example >= 13 and <= 19 => "Teen".
Should I always use braces with if statements?
Braces are optional when the body is a single statement, but most style guides recommend them anyway. Without braces, a second line added later looks as if it belongs to the if but runs every time. A short guard clause on one line, such as if (items.Count == 0) return;, is a common exception.
C# Control Flow Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the condition so the second message runs when the first condition is false.
if (age >= 18)
{
Console.WriteLine("Adult");
}
{
Console.WriteLine("Under 18");
}
What does this print?
int stock = 0;
Console.WriteLine(stock > 0 ? "Available" : "Sold out");
What does this print?
int n = 15;
string r = n switch { < 10 => "low", < 20 => "mid", _ => "high" };
Console.WriteLine(r);
What does _ mean in a switch expression?
What does x is >= 1 and <= 5 check?
C# Control Flow Quiz
5 questions to check what you learned.
What type must an if condition be?
- int
- string
- bool
- Any type
Which keyword ends a section in a switch statement?
- stop
- end
- exit
- break
What does a switch expression produce?
- Nothing
- A value
- A loop
- A method
What is a guard clause?
- A security feature
- An early check that returns from a method when a case is invalid
- A try block
- A type of loop
In an if, else if chain, how many blocks run?
- All true ones
- Always exactly two
- The last true one
- At most one: the first whose condition is true