Skip to content

Exception Handling

C# handles runtime errors with try/catch/finally. Code that might fail goes in try; catch blocks handle specific exception types (checked most-specific-first); finally runs regardless of whether an exception was thrown, commonly used for cleanup. You throw exceptions with throw new SomeException(...).

try
{
int result = 10 / int.Parse("0");
}
catch (DivideByZeroException ex)
{
Console.WriteLine($"Math error: {ex.Message}");
}
catch (FormatException ex)
{
Console.WriteLine($"Bad input: {ex.Message}");
}
finally
{
Console.WriteLine("Always runs, cleanup goes here");
}
public decimal Withdraw(decimal balance, decimal amount)
{
if (amount > balance)
throw new InvalidOperationException("Insufficient funds");
return balance - amount;
}
// Custom exception type
public class InsufficientFundsException : Exception
{
public InsufficientFundsException(string message) : base(message) { }
}

Catching Exception (the base type) too broadly, and worse, doing throw ex; to re-throw it β€” that resets the stack trace, making it look like the error originated in the catch block instead of where it actually happened.

try
{
ProcessOrder(order);
}
catch (Exception ex)
{
LogError(ex);
throw ex; // BAD: resets the stack trace, hides the real origin
}
// Correct: `throw;` alone preserves the original stack trace
catch (Exception ex)
{
LogError(ex);
throw; // re-throws the SAME exception with its original stack trace intact
}
  1. What’s the difference between throw ex; and throw; inside a catch block?

    Answerthrow ex; resets the stack trace to the point of the re-throw, hiding where the error actually originated; throw; alone re-throws the same exception object with its original stack trace preserved.
  2. When does the finally block execute?

    AnswerAlways β€” whether the try block completes successfully, throws an exception, or even returns early.
  3. Why should catch blocks generally target the most specific exception type possible, rather than the base Exception class?

    AnswerCatching narrowly lets you handle each failure mode appropriately and avoids accidentally swallowing unrelated bugs that happen to also derive from Exception.