C# Tutorial · Advanced C# · Lesson 18 of 22

C# Exceptions

try, catch, finally, throw, custom exceptions and using.

Handling exceptions

Example 1
try
{
    int[] arr = { 1, 2, 3 };
    Console.WriteLine(arr[5]);
}
catch (IndexOutOfRangeException e)
{
    Console.WriteLine($"Oops: {e.Message}");
}
finally
{
    Console.WriteLine("finally always runs");
}

try { int.Parse("abc"); }
catch (FormatException) when (DateTime.Now.Year > 2000) { Console.WriteLine("Not a number (filtered catch)"); }

Output

Oops: Index was outside the bounds of the array.
finally always runs
Not a number (filtered catch)

Run this on your computer — see “Get Started” for setup.

Custom exceptions and using

Derive from Exception for domain errors. using disposes resources (files, connections) automatically when they go out of scope:

Example 2
try
{
    using var conn = new FakeConnection("db");
    conn.Query("SELECT 1");
    throw new InsufficientFundsException(30m);
}
catch (InsufficientFundsException e)
{
    Console.WriteLine($"{e.Message} (short by {e.ShortBy})");
}

class InsufficientFundsException(decimal shortBy) : Exception("Insufficient funds")
{
    public decimal ShortBy { get; } = shortBy;
}

class FakeConnection : IDisposable
{
    private readonly string _name;
    public FakeConnection(string name) { _name = name; Console.WriteLine($"open {_name}"); }
    public void Query(string sql) => Console.WriteLine($"query: {sql}");
    public void Dispose() => Console.WriteLine($"close {_name}");
}

Output

open db
query: SELECT 1
close db
Insufficient funds (short by 30)

Run this on your computer — see “Get Started” for setup.

Test yourself

What does a using declaration guarantee?

  1. The namespace is imported
  2. Dispose() is called when the variable goes out of scope
  3. Exceptions are ignored
  4. The object is never null
Show answer

Answer: Dispose() is called when the variable goes out of scope