Loops & Conditionals in C#
Control flow is the "brain" of your application. It allows your program to make decisions, repeat actions, and handle different scenarios based on data.
1. Decision Making: Conditionals
The if, else if, and else Block
The most common way to branch logic.
int score = 85;
if (score >= 90)
{
Console.WriteLine("Grade: A");
}
else if (score >= 80)
{
Console.WriteLine("Grade: B");
}
else
{
Console.WriteLine("Try harder next time!");
}
The Ternary Operator (?:)
A concise way to assign a value based on a condition.
Syntax: condition ? value_if_true : value_if_false
int age = 20;
string accessLevel = (age >= 18) ? "Full Access" : "Restricted";
Switch Statements & Supported Types
The switch statement has evolved significantly. Historically, it was very restrictive, but modern C# (7.0 and later) allows you to switch on almost any type using pattern matching.
1. Traditional Constant Switching (Fast & Efficient)
In early versions of C#, you could only switch on types that the compiler could resolve as "constants" at compile time. This allows the compiler to create a Jump Table, which makes the switch statement much faster (O(1) complexity) than a long chain of if-else blocks.
Supported Types for Constants:
- Integral Types:
int,long,byte,short,uint, etc. - Char: Single characters (
'A','#'). - String: Text (C# handles string switching very efficiently using hash codes).
- Enums: Named constants (the most common use case).
- Bool: Though rarely used (an
ifis usually better).
2. Pattern Matching (The "Anything" Switch)
Since C# 7.0, the switch statement is no longer limited to constants. You can now switch on any object type, including custom classes, floats, and decimals, by using Patterns.
object data = 3.14m; // a decimal
switch (data)
{
case int i:
Console.WriteLine($"It's an integer: {i}");
break;
case decimal d when d > 3:
Console.WriteLine($"It's a large decimal: {d}");
break;
case string s:
Console.WriteLine($"It's a string of length {s.Length}");
break;
case null:
Console.WriteLine("It's null!");
break;
}
3. Types Historically "Not Supported" (And Why)
Historically, Floating-Point types (float, double) and Decimal were not allowed in traditional switch statements.
The Reason: Precision & Reliability
- Equality Issues: Floating-point numbers are notoriously imprecise.
0.1 + 0.2might result in0.30000000000000004. If the compiler allowed acase 0.3:, your code might never hit it even if the math "seems" correct. - Jump Table Complexity: Unlike integers, which map directly to memory offsets, floating-point ranges are harder to optimize into a fast "jump table."
Note: In modern C#, you CAN use them, but you are usually encouraged to use "relational patterns" (e.g., case > 0.5f:) rather than exact equality checks to avoid these precision bugs.
4. The "No-Go" Zone: What you still can't do
While you can switch on the type of almost anything, you cannot switch on:
- Expressions that aren't constants in a traditional case (e.g.,
case someVariable:is illegal; it must becase 10:). - Types without a valid equality check or pattern.
Switch Expressions (Modern C# 8.0+)
A more powerful and concise version of the switch statement that returns a value.
string color = "Red";
int priority = color switch
{
"Red" => 1,
"Yellow" => 2,
"Green" => 3,
_ => 0 // The discard '_' acts as the 'default' case
};
2. Iteration: Loops
The for Loop (Index-Based)
Use this when you know exactly how many times you want to repeat an action.
for (int i = 0; i < 10; i++)
{
Console.WriteLine($"Counting: {i}");
}
The foreach Loop (Collection-Based)
The most common loop in C#. It safely iterates over any collection that implements IEnumerable (like List or Array).
string[] fruits = { "Apple", "Banana", "Cherry" };
foreach (var fruit in fruits)
{
Console.WriteLine($"Eating a {fruit}");
}
The while Loop (Condition-Based)
Repeats as long as a condition is true. Check the condition before executing.
int energy = 100;
while (energy > 0)
{
Console.WriteLine("Working...");
energy -= 10; // Don't forget to update the condition variable!
}
The do-while Loop
Guarantees at least one execution because the condition is checked after the block.
string input;
do
{
Console.WriteLine("Type 'exit' to quit:");
input = Console.ReadLine();
} while (input != "exit");
3. Control Flow Keywords
break: Immediately exits the loop or switch.continue: Skips the rest of the current iteration and jumps to the next one.return: Exits the entire method.
Example: Finding the first even number and stopping
int[] numbers = { 1, 3, 5, 8, 10, 11 };
foreach (var n in numbers)
{
if (n % 2 == 0)
{
Console.WriteLine($"First even found: {n}");
break; // Stops the loop entirely
}
}
4. Logical & Relational Operators
To build complex conditions, we use:
&&(AND): True if both sides are true.||(OR): True if at least one side is true.!(NOT): Reverses the boolean value.==/!=: Equal / Not equal.>/</>=/<=: Comparison.
Short-Circuiting: C# is smart. In (false && expensiveMethod()), the second part is never run because the whole thing is already guaranteed to be false.
5. Practical Use Cases
Case A: Input Validation
Using do-while to ensure a user enters a valid number.
int validNumber;
bool isSuccess;
do
{
Console.Write("Enter a number between 1 and 10: ");
string input = Console.ReadLine();
isSuccess = int.TryParse(input, out validNumber);
} while (!isSuccess || validNumber < 1 || validNumber > 10);
Console.WriteLine($"Thank you for entering {validNumber}");
Case B: Filtering a List
Using foreach and if to process specific items.
var employees = new List<string> { "Alice_Dev", "Bob_HR", "Charlie_Dev", "Dave_Manager" };
var developers = new List<string>();
foreach (var emp in employees)
{
if (emp.EndsWith("_Dev"))
{
developers.Add(emp.Replace("_Dev", ""));
}
}
Case C: Simple Menu System
Using switch and while for a CLI menu.
bool running = true;
while (running)
{
Console.WriteLine("\n1. Start\n2. Settings\n3. Exit");
string choice = Console.ReadLine();
switch (choice)
{
case "1": Console.WriteLine("Game Starting..."); break;
case "2": Console.WriteLine("Settings Menu..."); break;
case "3": running = false; break;
default: Console.WriteLine("Invalid choice."); break;
}
}