Conditions and Loops: if, switch, for, while, foreach – C# | Lesson 32
Introduction
Until now, your program ran every line once, from top to bottom. Real school rules need two more abilities: deciding ("did Kabir pass?") and repeating ("do this for every installment").
Decisions are called conditions, and repetition is done with loops. With these two tools, the C# program can apply the same grading scale you wrote in SQL in Lesson 21.
By the end of this lesson, you will be able to:
- Write
if,else if, andelsewith comparison and logical operators. - Turn a mark into a grade with a
switchexpression. - Use the four loops:
for,while,foreach, anddo...while. - Control a loop with
breakandcontinue. - Choose the right loop for a task.
Why this matters
Every screen in the SMS is full of decisions: show "Paid" or "Unpaid", allow this mark or refuse it. Every report is full of repetition: one line per student, per day, per installment.
Getting a condition slightly wrong, such as > instead of >=, gives a student a grade
lower than they earned. Getting a loop wrong can freeze the program. Both mistakes are
common, and this lesson shows how to avoid them.
The concept
Example: if, else if, else
if (kabirMark >= PassMark)
{
Console.WriteLine("passed");
}
else
{
Console.WriteLine("needs a re-test");
}
The condition in brackets must be true or false. If it is true, the first block runs;
otherwise the else block runs.
Add else if (...) between them for more choices. Always use braces { }, even for one line.
Think of the school gate in the morning. If you have your ID card, you walk in; otherwise, you go to the office first. Every student takes exactly one path.
Example: comparison and logical operators
| Operator | Meaning | Example |
|---|---|---|
== / != | Equal / not equal | status == "Paid" |
> / >= | Greater / greater or equal | mark >= 33 |
< / <= | Less / less or equal | daysLate <= 14 |
&& | And: both must be true | mark >= 33 && attendedEnough |
|| | Or: at least one is true | mark < 33 || !attendedEnough |
! | Not: flips true and false | !isValid |
With mark = 67 and attendedEnough = true, the && line is True and the || line is
False. Note == for comparing; a single = puts a value into a variable.
Example: switch statement and switch expression
When one value decides between many choices, use switch. The classic switch
statement runs a block per case:
string status = "Late";
switch (status)
{
case "Present":
Console.WriteLine("Marked present");
break;
case "Late":
Console.WriteLine("Marked present, with a late note");
break;
default:
Console.WriteLine("Marked absent or on leave");
break;
}
It prints Marked present, with a late note. Each case ends with break, and default
catches everything else.
The newer switch expression produces a value instead. With relational patterns
such as >= 91, it fits grading perfectly; the arms are checked from top to bottom, and
_ means "anything else". You will see it in the program below.
Example: the ternary operator
For a choice between two values, condition ? valueIfTrue : valueIfFalse is a one-line
if:
string result = enteredMark >= PassMark ? "pass" : "re-test";
Use it for simple choices only. If you need to explain it, use if instead.
Example: the four loops
| Loop | Repeats | SMS example |
|---|---|---|
for | A known number of times, with a counter | 3 installments |
while | While a condition stays true; may run 0 times | Pay until the balance is 0 |
foreach | Once for each item in a collection | Each day in a week's register |
do...while | At least once, then while a condition is true | Ask until the mark is valid |
break leaves a loop at once. continue skips the rest of this round and starts the next.
Apply it to the SMS
The program applies school rules to real SchoolDb values: Kabir's and Aarav's Mathematics marks, and Diya's fee balance of 25,500 from Lesson 31.
Show src/SchoolApp.Console/Program.cs
// Lesson 32: conditions and loops, using 10-A's Mathematics marks and Diya's fee balance.
const int PassMark = 33;
// 1. if / else: did Kabir pass Mathematics?
decimal kabirMark = 67m;
if (kabirMark >= PassMark)
{
Console.WriteLine($"Kabir: {kabirMark} - passed");
}
else
{
Console.WriteLine($"Kabir: {kabirMark} - needs a re-test");
}
// 2. A switch expression turns a percentage into a grade (the same scale as fn_GetGrade).
decimal aaravPercentage = 92m;
string aaravGrade = aaravPercentage switch
{
>= 91 => "A1",
>= 81 => "A2",
>= 71 => "B1",
>= 61 => "B2",
>= 51 => "C1",
>= 41 => "C2",
>= 33 => "D",
_ => "E"
};
Console.WriteLine($"Aarav: {aaravPercentage}% -> grade {aaravGrade}");
// 3. for: split Diya's balance into 3 monthly installments.
decimal balance = 25500m;
int installments = 3;
decimal perInstallment = balance / installments;
DateOnly firstDue = new DateOnly(2026, 7, 31);
for (int i = 1; i <= installments; i++)
{
DateOnly due = firstDue.AddMonths(i - 1);
Console.WriteLine($"Installment {i}: {perInstallment} due {due:yyyy-MM-dd}");
}
// 4. while: pay up to 10,000 a month until nothing is left.
decimal remaining = 25500m;
int month = 0;
while (remaining > 0)
{
month++;
decimal payment = remaining >= 10000m ? 10000m : remaining;
remaining -= payment;
Console.WriteLine($"Month {month}: paid {payment}, remaining {remaining}");
}
// 5. foreach with continue: count the days attended in one week (P, L = attended; A = absent).
string week = "PPLAP";
int attended = 0;
foreach (char day in week)
{
if (day == 'A')
{
continue; // skip absent days
}
attended++;
}
Console.WriteLine($"Week {week}: attended {attended} of {week.Length} days");
// 6. do...while with break: ask until the user types a valid mark.
bool isValid;
decimal enteredMark;
do
{
Console.Write("Enter a mark from 0 to 100: ");
string? input = Console.ReadLine();
if (input == null)
{
break; // no more input: stop asking
}
isValid = decimal.TryParse(input, out enteredMark) && enteredMark >= 0 && enteredMark <= 100;
if (!isValid)
{
Console.WriteLine("That is not a valid mark. Try again.");
}
else
{
string result = enteredMark >= PassMark ? "pass" : "re-test";
Console.WriteLine($"Mark {enteredMark}: {result}");
}
} while (!isValid);
Run it, and type abc, then 150, then 85:
Kabir: 67 - passed
Aarav: 92% -> grade A1
Installment 1: 8500 due 2026-07-31
Installment 2: 8500 due 2026-08-31
Installment 3: 8500 due 2026-09-30
Month 1: paid 10000, remaining 15500
Month 2: paid 10000, remaining 5500
Month 3: paid 5500, remaining 0
Week PPLAP: attended 4 of 5 days
Enter a mark from 0 to 100: abc
That is not a valid mark. Try again.
Enter a mark from 0 to 100: 150
That is not a valid mark. Try again.
Enter a mark from 0 to 100: 85
Mark 85: pass
Example: the grade switch
Aarav's 92 matches the first arm, >= 91, so the grade is A1. The order of the arms
matters: for 92, >= 81 is also true, but the switch stops at the first match.
This is the same scale as fn_GetGrade in SQL. When a rule exists in two places, both
must change together. Module 7 shows how to keep such rules in one shared place.
Example: the for loop
for (int i = 1; i <= installments; i++) has three parts: start at 1, continue while
i <= 3, and add 1 after each round. The loop body runs exactly three times.
Look at the third due date: 30 September, not 31. AddMonths knows September has 30 days.
Using the date types from Lesson 31 saves you from writing that rule yourself.
Example: the while loop
The while loop does not know in advance how many months it needs. It checks
remaining > 0 before each round, and stops after month 3, when the remaining amount
reaches 0.
The line remaining -= payment; is short for remaining = remaining - payment;. If you
forgot it, remaining would never change, and the loop would run forever.
Example: foreach and continue
A string is a sequence of characters, so foreach can walk through "PPLAP" one day at
a time. On the A day, continue skips the counting line. Four of five days count as
attended.
The SchoolDb register stores whole words, such as Present. A letter per day is just a
compact way to type one week here.
Example: do...while and break
The question must be asked at least once, so do...while fits. It repeats while the input
is not valid: abc is not a number, and 150 is above 100.
The break handles a quiet danger. If the input ends, for example when the program reads
from a file instead of a person, ReadLine returns null. Without the break, the loop
would ask forever.
Common mistakes
=instead of==in a condition.if (mark = 33)fails witherror CS0029: Cannot implicitly convert type 'int' to 'bool'. Fix: use==to compare.>instead of>=at a boundary. A student with exactly 91 gets A2. Fix: test the exact boundary values, such as 33, 90, and 91.- A switch expression without
_. The compiler warnsCS8509: The switch expression does not handle all possible values, and an unmatched value stops the program withSwitchExpressionException. Fix: always end with a_arm. - A loop that never ends. The condition never becomes false. Fix: make sure every
round moves toward the end, such as reducing
remaining. - Missing braces. A second line added to a braceless
ifalways runs. Fix: use braces every time.
In real projects
A school once complained that students with exactly 33 marks were shown as failed. The
code said mark > 33. One character cost a week of angry parents and a re-run of report cards.
Since then, every grading or fee rule I write gets tests at its exact boundaries: 32, 33, and 34; 90 and 91. Most condition bugs live exactly on the edge.
Loops taught me a similar habit: before running a while loop on real data, I ask "what
makes this stop?" If I cannot answer in one sentence, the loop is not ready.
Best practices
- Use braces for every
if,else, and loop body. - Use constants such as
PassMarkinstead of numbers inside conditions. - Prefer a
switchexpression with a_arm for many-way choices. - Pick the loop that matches the task: count, condition, collection, or "at least once".
- Test conditions at their exact boundary values.
Recap
if,else if, andelsechoose one path based on a true or false condition.&&,||, and!combine conditions;==compares,=assigns.- A switch expression with relational patterns turns marks into grades; arms are checked in order.
forcounts,whilechecks first,foreachwalks a collection,do...whileruns at least once.breakleaves a loop;continueskips to the next round.
Homework
Library module task: Print a fine table for 0 to 30 days late, in steps of 5. Calculate each fine at 2 per day. Label each row "on time" for 0 days, "late" for up to 14 days, and "very late" after that.
A correct result looks like:
0 days: fine 0 (on time)
5 days: fine 10 (late)
10 days: fine 20 (late)
15 days: fine 30 (very late)
20 days: fine 40 (very late)
25 days: fine 50 (very late)
30 days: fine 60 (very late)
Show the solution
// Library homework, Lesson 32: a fine table for 0 to 30 days late, in steps of 5.
// Run with: dotnet run library-assignment/032-library-fine-table.cs
const decimal FinePerDay = 2m;
for (int daysLate = 0; daysLate <= 30; daysLate += 5)
{
decimal fine = daysLate * FinePerDay;
string label = daysLate switch
{
0 => "on time",
<= 14 => "late",
_ => "very late"
};
Console.WriteLine($"{daysLate,2} days: fine {fine,3} ({label})");
}
daysLate += 5 moves the counter in steps of 5. In {daysLate,2}, the ,2 pads the
number to two characters, so the columns line up.
Quiz
Which operator compares two values for equality?
Show answer
Answer: B. == A single = assigns a value; == compares.
A switch expression has arms >= 91, >= 81, >= 71 in that order. Which arm matches 92?
Show answer
Answer: A. >= 91 Arms are checked from top to bottom, and the first match wins.
Which loop always runs its body at least once?
Show answer
Answer: D. do...while do...while checks its condition after each round.
What does continue do inside a loop?
Show answer
Answer: B. Skips the rest of this round and starts the next break leaves the loop; continue moves to the next round.
Which loop fits 'pay 10,000 a month until the balance is 0'?
Show answer
Answer: B. while, checking the balance The number of months is not known in advance; the balance decides.
Interview questions
Questions are grouped by experience level. Click a question to see a model answer. All questions: C# interview questions.
Fresher (0-2 yrs)
F What is the difference between = and == in C#? concept
= assigns a value to a variable; == compares two values and returns true or false.
Writing if (mark = 33) does not compile in C#: error CS0029, because an int is not a bool.
F What are the four loops in C#, and when do you use each? concept
for repeats a known number of times with a counter; while repeats while a condition is
true and may run zero times; foreach visits each item in a collection; do...while runs at
least once and then checks its condition.
F What is the difference between break and continue? concept
break leaves the loop immediately. continue skips the rest of the current round and starts
the next one. In a switch statement, break ends each case.
Mid (3-5 yrs)
M What is the difference between a switch statement and a switch expression? concept
A switch statement runs a block of code per case, with case, break, and default. A switch
expression produces a value from arms like >= 91 => "A1", checked from top to bottom, with _
for anything else. Switch expressions are shorter for mapping one value to another.
M What happens if a switch expression has no arm that matches the value? concept
The compiler warns with CS8509 that the switch is not exhaustive, and at run time an unmatched
value throws SwitchExpressionException. Always end with a _ discard arm.
M What does the ternary operator do, and when should you avoid it? concept
condition ? a : b returns a when the condition is true, otherwise b, as a one-line if.
Avoid it when the condition or values are complex, or when nested ternaries make the code hard
to read; use if or a switch expression instead.
Senior (6-9 yrs)
S Students with exactly 33 marks are shown as failed. How do you find and prevent this kind of bug? scenario
It is a boundary error: the condition uses > where the rule says "33 or more", so it should be
>=. Fix the operator, use a named constant such as PassMark, and add tests at the exact
boundaries (32, 33, 34) for every rule.
How to answer: Explain the off-by-one cause, the fix, and the prevention: boundary-value tests and rules kept in one place. Mention re-checking data already produced with the wrong rule.
S A console tool that reads input in a loop hangs forever when run by a scheduled job. Why, and how do you fix it? scenario
When input comes from a file or a job, it can end; Console.ReadLine then returns null every
time, so a validation loop never gets valid input. Check for null and break, and design
batch tools to read arguments or files instead of prompting.
How to answer: Show you think about every way a loop can end, including end of input. Mention timeouts and clear exit codes for tools run by schedulers.
Architect / Lead (10+ yrs)
A The grading scale exists in SQL (fn_GetGrade) and in C#. How would you keep business rules consistent? design
Keep each rule in one authoritative place where possible, for example in a shared C# library used by every application, or in the database when reports depend on it. If a rule must exist twice, document it, test both against the same boundary cases, and change them together.
How to answer: Discuss the trade-off between one source of truth and practical needs such as SQL reports, then the safety nets: shared test cases, code review checklists, and configuration-driven rules.
Resources
- Code for this lesson: git tag
lesson-32-conditions-loops(code repository coming soon) - Files:
src/SchoolApp.Console/Program.cs,library-assignment/032-library-fine-table.cs - Video: coming soon
What's next
Your program can decide and repeat, but it still holds one mark at a time. Next: arrays, which hold all of 10-A's marks together, and strings, which hold names and admission numbers. Lesson 33: Arrays and strings
Want live sessions, code reviews, and interview preparation? Join the next batch at Sahasra Technologies.