C# Exception Handling Guide

Exception Handling in C#

  1. Understanding Exceptions

Exception handling aims to respond to exceptions by performing one or more of the following actions: correction, logging, external resource cleanup, or providing user-friendly messages.

  1. The try Block

The try block contains code segments protected against exceptions, with handlers provided for when they occur. A catch block contains one or more handlers for exceptions. The finally block includes code that must execute under all circumstances.

  1. Exception Classes

The Base Class Library defines numerous exception classes, each representing a specific type of exception. When an exception occurs, the CLR creates an object of that exception type and searches for an appropriate catch clause. All exceptions derive from System.Exception.

Exception objects contain read-only properties that provide details about the error.

Property Type Description
Message string Contains a message explaining the cause of the exception.
StackTrace string Describes where the exception occurred.
InnerException Exception If the current exception was caused by another, this holds a reference to the previous exception.
Source string If not set by the application, contains the name of the assembly where the exception originated.
  1. catch Clauses

There are four forms of catch clauses, allowing differant levels of handling:

4.1 General catch

Matches any exception type thrown within the try block. It can handle any exception but cannot determine the specific exception type.

catch
{
    // Statements
}

4.2 Specific catch

Matches exceptions of a specified class or its derived classes.

catch(ExceptionType)
{
    // Statements
}

4.3 Specific catch with object

Includes an identifier after the exception class name, creating an exception variable that can be accessed within the catch block to obtain detailed information about the exception.

catch(ExceptionType ExceptionVar)
{
    // Statements
}

4.4 Specific catch with predicate

Execution enters this clause only when the predicate evaluates to true.

catch(ExceptionType ExceptionVar) when (predicate)
{
    // Statements
}

Example

int numerator = 10;
try
{
    int denominator = 0;
    int result = numerator / denominator; // Throws exception
}
catch (DivideByZeroException ex)
{
    Console.WriteLine($"1. {ex.Message}");
    Console.WriteLine($"2. {ex.Source}");
    Console.WriteLine($"3. {ex.StackTrace}");
}
  1. Exception Filters

A single exception type can have multiple handlers. The exception object is past to the handler when the catch clause's conditions are satisfied.

try
{
    // Code that may throw exceptions
}
catch (HttpRequestException ex) when (ex.Message.Contains("307"))
{
    // Handle 307 redirect
}
catch (HttpRequestException ex) when (ex.Message.Contains("301"))
{
    // Handle 301 redirect
}

Key properties of the when clause:

  • Must contain a predicate expression returning true or false.
  • Cannot be asynchronous.
  • Should not involve long-running operations.
  • Exceptions within the predicate expression are ignored while preserving debugging information.
  1. catch Clause Section

If a catch clause accepts a parameter, the system sets this exception variable to reference the exception object, anabling inspection to determine the cause. If the exception resulted from a previous exception, the InnerException property provides access to it.

Multiple catch clauses are allowed, but only one general catch clause is permitted. When an exception occurs, the system searches the catch clauses in order; the first matching clause executes. Therefore, two important rules apply:

  1. Specific catch clauses must be ordered from most specific to most general (subclass exceptions before parent class exceptions).

  2. If a general catch clause exists, it must be last, following all specific catch clauses. Its use is discouraged as it may allow program continuation while hiding errors.

  3. finally Block


If no exception occurs within the try block, control flows to the finally block after the try block ends. If an exception occurs, the appropriate catch clause executes, followed by the finally block.

  1. Locating Exception Handlers

When an exception occurs within a try block, the system checks for a matching catch clause. If found, one of three actions occurs:

  1. The catch clause executes.

  2. If a finally block exists, it executes.

  3. Execution continues after the try statement (after the finally block if present, otherwise after the last catch clause).

  4. Further Search


If an exception is thrown in code not protected by try or without a matching handler, the system searches the call stack sequentially for an enclosing try block with a matching handler.

Example

static void Main(string[] args)
{
    Processor processor = new Processor();
    try
    {
        processor.MethodA();
    }
    catch (DivideByZeroException)
    {
        Console.WriteLine("catch in Main");
    }
    finally
    {
        Console.WriteLine("finally in Main");
    }
    Console.WriteLine("Main continues");
}

class Processor
{
    public void MethodA()
    {
        try
        {
            MethodB();
        }
        catch(IndexOutOfRangeException)
        {
            Console.WriteLine("catch in MethodA");
        }
        finally
        {
            Console.WriteLine("finally in MethodA");
        }
    }
    
    void MethodB()
    {
        int value = 10;
        int divisor = 0;
        try
        {
            int quotient = value / divisor;
        }
        catch(IndexOutOfRangeException)
        {
            Console.WriteLine("catch in MethodB");
        }
        finally
        {
            Console.WriteLine("finally in MethodB");
        }
    }
}
  1. Throwing Exceptions

throw new ExceptionType();
  1. Throwing Without Exception Object - Re-throwing

The throw statement can be used without an exception object inside a catch block. This form re-throws the current exception, causing the system to continue searching for another handler. This form is only valid inside catch statements.

public static void DisplayArgument(string arg)
{
    try
    {
        try
        {
            if(arg == null)
            {
                ArgumentException invalidArg = new ArgumentException();
                throw invalidArg;
            }
            Console.WriteLine(arg);
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine($"{ex.Message}");
            throw; // Re-throw without parameter
        }
    }
    catch
    {
        Console.WriteLine("outer catch handles Exception");
    }
}
  1. throw Expressions

Throw expressions can be used where expressions are permitted. They function similarly to throw statements but as expressions.

Using throw with Null-Coalescing Operator

The null-coalescing operator (??) returns the first operand if not null, otherwise the second.

private int securityIdentifier;
public int SecurityIdentifier
{
    get => securityIdentifier;
    set => securityIdentifier = value ?? throw new ArgumentNullException("Security identifier cannot be null");
}

Using throw in Ternary Expressions

class SecurityManager
{
    public static string AccessCode { get { return "Confidential123"; } }
    
    static void Main()
    {
        bool isSecure = false;
        try
        {
            string code = isSecure ? AccessCode : throw new Exception("Security check failed");
            Console.WriteLine($"Code: {code}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"{ex.Message}");
        }
    }
}

Tags: C# Exception Handling Try-Catch-Finally throw CLR

Posted on Thu, 24 Sep 2026 16:34:08 +0000 by Cramblit