<style> .reveal-up, .reveal-left, .reveal-right, .reveal-stagger > * { opacity: 1 !important; transform: none !important; } </style>
  1. Learn
  2. C#
  3. Working with data
All lessons in this course

Lesson 30 of 60 15 minIntermediate

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.

Files go missing, users type letters into number fields, networks drop. When .NET hits a problem it can’t handle on the spot, it throws an exception: an object describing what went wrong. If nothing catches it, the program crashes. Exception handling lets you respond sensibly instead.

Interactive

Follow an exception

input =
Divide.cs
string input = "abc";try{    int a = int.Parse(input);    int result = 100 / a;    Console.WriteLine($"Result: {result}");}catch (FormatException){    Console.WriteLine("Please type a number.");}catch (DivideByZeroException ex){    Console.WriteLine($"Error: {ex.Message}");}finally{    Console.WriteLine("Done.");}Console.WriteLine("Program continues");
Step 1 / 5
Inside try: int.Parse tries to turn the text into a number.

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

ExceptionTypical cause
NullReferenceExceptionusing a member of a null reference
IndexOutOfRangeExceptionarray index outside 0..Length-1
ArgumentOutOfRangeExceptiona list index or argument out of the allowed range
FormatExceptionint.Parse("abc")
DivideByZeroExceptioninteger division by 0
InvalidOperationExceptionthe object isn’t in the right state (e.g. Pop() on an empty stack)
FileNotFoundExceptionopening a file that doesn’t exist
KeyNotFoundExceptiondict[key] with a missing key

The exception object

Details.cs
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}
Output
Missing file: D:\Work\model.ifc
Could not find file 'D:\Work\model.ifc'.

Throwing your own

Throw.cs
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}") { }}

Throw when a method can’t do what its name promises: invalid arguments, impossible state. Prefer the built-in types (ArgumentException, InvalidOperationException) and create custom ones (always ending in Exception) for domain-specific errors that callers might want to catch separately.

Re-throwing correctly

Rethrow.cs
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

Filter.cs
catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound){    Console.WriteLine("Not found on the server");}

Good practice

  • Prevent before you catch: use TryParse, check for null, check Count. 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) or finally to release files and connections.
Quick check

When does a finally block run?

Quick check

Which is the best way to re-throw a caught exception?

Practice

Write 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
Solution.cs
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" }));
Output
Skipping 'x'
15

Remember

  • Exceptions are objects thrown when something goes wrong; uncaught ones crash the program.
  • Catch specific types first; finally always runs.
  • Throw meaningful exceptions for invalid input or state; re-throw with throw;.
  • Prevent common errors (TryParse, null checks) instead of relying on catch.
0 of 60 lessons completed