C# Exceptions

An exception is an error that happens while your program is running, such as dividing by zero, opening a file that does not exist, or converting text that is not a number. If you do nothing, an exception stops your program with an error message. C# gives you try-catch blocks so you can catch these errors, deal with them calmly, and keep your program running.

The try and catch Blocks

You put the risky code inside a try block. If an exception occurs, C# immediately jumps to the matching catch block instead of crashing. The catch block receives an exception object that describes what went wrong, which you can read through its Message property.

Catching a division error

using System;

class Program
{
    static void Main()
    {
        try
        {
            int[] numbers = { 10, 20, 30 };
            Console.WriteLine(numbers[5]);
        }
        catch (IndexOutOfRangeException ex)
        {
            Console.WriteLine("Oops: " + ex.Message);
        }

        Console.WriteLine("The program keeps running.");
    }
}

// Output:
// Oops: Index was outside the bounds of the array.
// The program keeps running.

Common Exception Types

Different problems throw different types of exceptions. You can catch a specific type to handle it in a targeted way, or catch the general Exception type to handle anything. Here are some you will meet often.

Exception typeWhen it happens
DivideByZeroExceptionDividing an integer by zero
IndexOutOfRangeExceptionUsing an index that is outside an array
FormatExceptionConverting text that is not in the expected format
FileNotFoundExceptionOpening a file that does not exist
NullReferenceExceptionUsing an object that is null

Catching Specific Exceptions

You can stack several catch blocks after a single try. C# checks them from top to bottom and runs the first one whose type matches the error. Put the most specific types first and a general one last.

Handling a file that might not exist

using System;
using System.IO;

class Program
{
    static void Main()
    {
        try
        {
            string text = File.ReadAllText("missing.txt");
            Console.WriteLine(text);
        }
        catch (FileNotFoundException)
        {
            Console.WriteLine("The file could not be found.");
        }
        catch (Exception ex)
        {
            Console.WriteLine("Unexpected error: " + ex.Message);
        }
    }
}

// Output:
// The file could not be found.

The finally Block

An optional finally block runs after try and catch no matter what happens, whether an exception was thrown or not. It is the perfect place for cleanup work, such as closing files or releasing resources, so it always runs.

Using finally for cleanup

using System;

class Program
{
    static void Main()
    {
        try
        {
            string input = "abc";
            int value = int.Parse(input);
            Console.WriteLine(value);
        }
        catch (FormatException)
        {
            Console.WriteLine("That was not a valid number.");
        }
        finally
        {
            Console.WriteLine("Done processing.");
        }
    }
}

// Output:
// That was not a valid number.
// Done processing.
Note: Only catch exceptions you actually know how to handle. Catching every error and doing nothing hides real bugs. A good catch block should log, recover, or clearly inform the user.
  • Put risky code in a try block.
  • Handle errors in one or more catch blocks.
  • Use ex.Message to read what went wrong.
  • Use finally for cleanup that must always run.

Exercise: C# Exceptions

When does code inside a `finally` block run?