Exceptions: try, catch, finally, throw
Handle errors without crashing: catch specific exceptions, clean up with finally, throw your own and know when not to catch.
try / catch / finally
try: the code that might fail. As soon as an exception is thrown, the rest of the block is skipped. catch (Type ex): runs only if the exception matches that type (or a subclass). Checked top to bottom; the first match wins. finally: always runs, success or failure. Used to release resources (close files, connections).
Common exception types
| Exception | Typical cause |
|---|---|
NullReferenceException | null reference |
IndexOutOfRangeException | |
ArgumentOutOfRangeException | |
FormatException | int.Parse("abc") |
DivideByZeroException | |
InvalidOperationException | Pop() on an empty stack) |
FileNotFoundException | |
KeyNotFoundException | dict[key] with a missing key |
The exception object
try{ string text = File.ReadAllText("model.ifc");}catch (FileNotFoundException ex){ Console.WriteLine($"Missing file: {ex.FileName}"); Console.WriteLine(ex.Message); // human-readable description // ex.StackTrace shows where it happened: log it for developers}Missing file: D:\Work\model.ifc Could not find file 'D:\Work\model.ifc'.
Throwing your own
public class Beam{ public Beam(double lengthM) { if (lengthM <= 0) throw new ArgumentOutOfRangeException(nameof(lengthM), lengthM, "Length must be positive."); LengthM = lengthM; } public double LengthM { get; }} // Custom exception for your own domain errorspublic class ClashDetectedException : Exception{ public ClashDetectedException(string a, string b) : base($"{a} clashes with {b}") { }}ArgumentException, InvalidOperationException) and create custom ones (always ending in Exception) for domain-specific errors that callers might want to catch separately.
Re-throwing correctly
try{ SaveProject();}catch (IOException ex){ Log(ex); // record it… throw; // …and let it continue upwards with its ORIGINAL stack trace // throw ex; // ✗ resets the stack trace: you lose where it really happened}Exception filters
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound){ Console.WriteLine("Not found on the server");}Good practice
Prevent before you catch: use TryParse, check fornull, checkCount. Exceptions are for exceptional situations, and they are slow.Catch only what you can handle meaningfully. Never write an empty catch { }that silently hides errors.Catch Exception(everything) only at the top level of the app, to log the error and show a friendly message.Use using(next module) orfinallyto release files and connections.
static double SafeAverage(string[] inputs) that converts each string with double.Parse and returns the average. Catch FormatException per item (skip it and print a warning) and throw InvalidOperationException if no valid numbers remain. Test with { "10", "x", "20" }.
Show the solution
using System.Globalization; static double SafeAverage(string[] inputs){ double sum = 0; int count = 0; foreach (string s in inputs) { try { sum += double.Parse(s, CultureInfo.InvariantCulture); count++; } catch (FormatException) { Console.WriteLine($"Skipping '{s}'"); } } if (count == 0) throw new InvalidOperationException("No valid numbers."); return sum / count;} Console.WriteLine(SafeAverage(new[] { "10", "x", "20" }));Skipping 'x' 15
Remember
Exceptions are objects thrown when something goes wrong; uncaught ones crash the program. Catch specific types first; finallyalways runs.Throw meaningful exceptions for invalid input or state; re-throw with throw;.Prevent common errors ( TryParse, null checks) instead of relying on catch.