Lesson 19 — Handling Errors
Exception Handling
C# exception handling adds exception filters (when) and better rethrowing semantics over Java. The pattern is critical for every professional application.
CSHARP — try/catch/finally
try {
int result = 10 / 0;
}
catch (DivideByZeroException ex) {
Console.WriteLine($"Cannot divide by zero: {ex.Message}");
}
finally {
Console.WriteLine("Operation complete — this always runs.");
}
Exception Filters
CSHARP — Exception filters
// when clause — catch only if condition is true:
try {
// database or network operation
}
catch (SqlException ex) when (ex.Number == 1205) {
Console.WriteLine("Deadlock detected — retrying...");
}
catch (SqlException ex) when (ex.Number == -2) {
Console.WriteLine("Query timeout — consider optimising.");
}
catch (Exception ex) {
Console.WriteLine($"Unexpected: {ex.Message}");
}
// Rethrowing — bare throw preserves the stack trace:
catch (Exception ex) {
Log(ex); // log it
throw; // rethrow without altering the stack trace
// throw ex; // BAD — resets the stack trace to this line
}
Custom Exceptions
CSHARP — Custom exceptions
public class InsufficientFundsException : Exception {
public decimal Shortfall { get; }
public InsufficientFundsException(decimal shortfall)
: base($"Insufficient funds. Short by R{shortfall:F2}.") {
Shortfall = shortfall;
}
}
// In BankAccount:
public void Withdraw(decimal amount) {
if (amount > Balance)
throw new InsufficientFundsException(amount - Balance);
Balance -= amount;
}
// Usage:
try { account.Withdraw(5000m); }
catch (InsufficientFundsException ex) {
Console.WriteLine(ex.Message);
Console.WriteLine($"Need R{ex.Shortfall:F2} more.");
}
Practice Task
Your Turn
Write a LearnerDatabase with custom exceptions: DatabaseFullException, LearnerNotFoundException, InvalidMarkException. Implement Add(Learner l), Get(int index), and UpdateMark(int index, double mark). Test every exception path in Main.
Common Mistakes
- Empty catch blocks — hiding errors is worse than crashing.
- throw ex; resets the stack trace — always use bare throw;
- Catching Exception everywhere — catch the most specific type you can handle.
- Using exceptions for normal flow control — they are expensive and for exceptional conditions only.
Professional Tip
Print ex.StackTrace during development to see exactly where and why an exception occurred. In production, use structured logging (Serilog, NLog) instead of Console.WriteLine.
Mini Quiz
What does bare throw; (no argument) do inside a catch block?
throw; rethrows without modifying the stack trace. throw ex; would reset it, making debugging much harder.