Let’s go through using multiple catch blocks with exception hierarchy in C# β€” this is important for fine-grained exception handling.


πŸ“Œ 1. Exception Hierarchy in C#

  • All exceptions in C# inherit from the base class System.Exception.

  • Examples:

Exception (base class)
 β”œβ”€ System.IO.IOException
 β”‚    β”œβ”€ System.IO.FileNotFoundException
 β”‚    └─ System.IO.DirectoryNotFoundException
 └─ System.NullReferenceException
  • Understanding hierarchy helps decide which catch blocks to use and their order.

πŸ“Œ 2. Multiple Catch Blocks

  • You can write several catch blocks to handle specific exceptions differently.

  • Order matters: always catch more specific exceptions first, then general ones.

Syntax Example

class Program
{
    static void Main()
    {
        try
        {
            string path = "nonexistentfile.txt";
            string content = System.IO.File.ReadAllText(path);
        }
        catch (System.IO.FileNotFoundException ex)
        {
            Console.WriteLine("File not found: " + ex.Message);
        }
        catch (System.IO.IOException ex)
        {
            Console.WriteLine("IO Exception: " + ex.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine("Other exception: " + ex.Message);
        }
    }
}

Output:

File not found: Could not find file 'nonexistentfile.txt'.
  • FileNotFoundException is more specific than IOException, so it is caught first.

πŸ“Œ 3. Key Rules

  1. Most specific first

    • Catch specific exceptions before general ones (Exception).

    • Otherwise, the general catch will swallow the specific exception, and the compiler may warn you.

  2. General catch last

    • Usually catch (Exception ex) or catch as a final fallback.
  3. Optional finally

    • A finally block runs regardless of which catch executed (or if none executed).
finally
{
    Console.WriteLine("Cleanup resources here.");
}

πŸ“Œ 4. Example With Hierarchy and Cleanup

try
{
    int[] arr = new int[2];
    Console.WriteLine(arr[5]); // IndexOutOfRangeException
}
catch (NullReferenceException ex)
{
    Console.WriteLine("Null reference!");
}
catch (IndexOutOfRangeException ex)
{
    Console.WriteLine("Index out of range!");
}
catch (Exception ex)
{
    Console.WriteLine("Other exception: " + ex.Message);
}
finally
{
    Console.WriteLine("This always runs.");
}

Output:

Index out of range!
This always runs.

πŸ“Œ 5. Analogy

  • Think of catch blocks like nested nets:

    • Smaller, specific nets catch specific fish first.

    • Bigger, general nets catch anything left over.

  • Order matters β€” general nets first and smaller nets later means you lose specificity.


βœ… Summary:

  • Use multiple catch blocks to handle exceptions differently based on type.

  • Catch specific exceptions first, then more general ones.

  • finally ensures cleanup always happens.