6. Exception Handling


1. What are Exceptions?

Error vs Exception

Error - Programming mistakes caught at compile-time

int x = "hello";  // Compile-time error

Exception - Runtime problems that occur during program execution

int[] numbers = { 1, 2, 3 };
int x = numbers[10];  // Runtime exception (IndexOutOfRangeException)

Exception Hierarchy

System.Object

    └─ System.Exception (base for all exceptions)

        ├─ System.SystemException (runtime errors)
        │   ├─ NullReferenceException
        │   ├─ IndexOutOfRangeException
        │   ├─ InvalidOperationException
        │   ├─ ArgumentException
        │   │   ├─ ArgumentNullException
        │   │   └─ ArgumentOutOfRangeException
        │   ├─ DivideByZeroException
        │   ├─ OverflowException
        │   ├─ StackOverflowException
        │   ├─ OutOfMemoryException
        │   ├─ FormatException
        │   └─ InvalidCastException

        ├─ System.IO.IOException
        │   ├─ FileNotFoundException
        │   ├─ DirectoryNotFoundException
        │   └─ EndOfStreamException

        └─ Custom exceptions (derive from Exception)
            └─ MyCustomException

2. Common Exception Types

Exception
When Thrown
Example

NullReferenceException

Accessing null reference

string s = null; s.Length;

IndexOutOfRangeException

Invalid array/list index

arr[100] when arr.Length < 100

ArgumentNullException

Null argument passed

Method receives null when not allowed

ArgumentException

Invalid argument

Method receives invalid value

ArgumentOutOfRangeException

Argument out of range

list.RemoveAt(-1)

InvalidOperationException

Invalid state for operation

Call method when object in wrong state

DivideByZeroException

Division by zero

x / 0 (integer division)

FormatException

Invalid format in conversion

int.Parse("abc")

InvalidCastException

Invalid type cast

(int)"hello"

OverflowException

Arithmetic overflow

checked { int x = int.MaxValue + 1; }

FileNotFoundException

File not found

File.Open("missing.txt")

IOException

I/O operation failed

File access error

NotImplementedException

Method not implemented

Placeholder methods

NotSupportedException

Operation not supported

Feature not available

System-Level vs Application-Level Exceptions

System Exceptions (SystemException) - Thrown by .NET runtime

Application Exceptions - ❌ DEPRECATED approach

Modern Approach - ✅ Derive directly from Exception


3. Try-Catch-Finally

Basic Structure

Try-Catch-Finally Flow

Catching Specific Exceptions

Exception Filters (C# 6.0+)


4. Multiple Catch Clauses

Order Matters! (Most Specific First)

Multiple Exceptions in One Catch (C# 6.0+)


5. Nesting Try-Catch Blocks


6. Throwing Exceptions

throw Keyword

throw vs throw ex (CRITICAL!)

Throw Expressions (C# 7.0+)


7. Custom Exceptions

Creating Custom Exceptions

Best Practices for Custom Exceptions

Do:

  • End name with "Exception" (e.g., ValidationException)

  • Derive from Exception (not ApplicationException)

  • Provide at least 3 constructors (default, message, message + inner)

  • Include relevant context in properties

  • Document when your exception is thrown

Don't:

  • Derive from SystemException or ApplicationException

  • Throw generic Exception type

  • Use exceptions for control flow


8. Exception Properties

Walking the Exception Chain


9. Best Practices

When to Catch Exceptions

DO catch when:

  • You can handle the error and recover

  • You need to add context before re-throwing

  • You need to clean up resources

  • At application boundaries (UI, API endpoints)

  • You need to log the error

DON'T catch when:

  • You can't do anything about it

  • It would hide bugs (like NullReferenceException in your code)

  • It's a programming error that should be fixed

  • You're just going to re-throw it without adding value

Specific vs General Exceptions

Don't Use Exceptions for Control Flow

Log Exceptions

Fail Fast Principle


10. Resource Management

IDisposable Pattern

IDisposable Interface

Purpose: Clean up unmanaged resources (file handles, database connections, network sockets)

Basic Implementation

Full Dispose Pattern (with Finalizer)

using Statement (C# 1.0)

Purpose: Automatically call Dispose() when scope exits

Multiple Resources

using Declaration (C# 8.0+)

Simplified syntax - disposes at end of containing scope

IAsyncDisposable (C# 8.0+)

Purpose: Asynchronous resource cleanup

using Statement Evolution


11. Exception Handling with Async

try-catch in Async Methods

AggregateException

When multiple tasks fail:

Handling Task Exceptions


Common Patterns

Pattern 1: Try-Parse

Pattern 2: Retry Logic

Pattern 3: Exception Translation

Pattern 4: Safe Disposal


Anti-Patterns (What NOT to Do)

❌ Empty Catch Block

❌ Catching Exception Without Re-throwing

❌ throw ex Instead of throw

❌ Exception for Control Flow

❌ Catching and Doing Nothing


Decision Tree: Should I Catch This Exception?


Quick Reference Summary

Exception Hierarchy

  • All exceptions derive from System.Exception

  • Catch specific exceptions, not Exception (unless at boundary)

  • Order catches from most specific to most general

Try-Catch-Finally

  • try - Code that might throw

  • catch - Handle exception

  • finally - Always executes (cleanup)

Throwing

  • throw - Preserves stack trace ✅

  • throw ex - Loses stack trace ❌

  • throw new Exception("message", innerException) - Wrap exception

Resource Management

  • Implement IDisposable for cleanup

  • Use using statement/declaration

  • Use await using for async resources

  • Always dispose resources in finally or using

Best Practices

  • ✅ Catch specific exceptions

  • ✅ Log exceptions

  • ✅ Clean up resources

  • ✅ Fail fast

  • ✅ Use try-parse instead of try-catch

  • ❌ Don't use exceptions for control flow

  • ❌ Don't catch and do nothing

  • ❌ Don't use throw ex


Guide Complete! Master these exception handling patterns and you'll write robust, production-ready C# code! 📘

Last updated