Skip to content

C# Exception Handling

Overview

Exception handling provides a structured way to handle runtime errors and exceptional conditions in your code.

Basic Exception Handling

Try-Catch Block

csharp
try
{
    int x = 10;
    int y = 0;
    int result = x / y; // DivideByZeroException
}
catch (DivideByZeroException ex)
{
    Console.WriteLine($"Cannot divide by zero: {ex.Message}");
}
catch (Exception ex)
{
    Console.WriteLine($"General error: {ex.Message}");
}
finally
{
    Console.WriteLine("Cleanup code here");
}

Multiple Catch Blocks

csharp
try
{
    string input = "abc";
    int number = int.Parse(input); // FormatException
}
catch (FormatException ex)
{
    Console.WriteLine($"Invalid number format: {ex.Message}");
}
catch (OverflowException ex)
{
    Console.WriteLine($"Number too large: {ex.Message}");
}
catch (Exception ex)
{
    Console.WriteLine($"Unexpected error: {ex.Message}");
}

Custom Exceptions

csharp
public class InvalidAgeException : Exception
{
    public InvalidAgeException() : base("Invalid age provided") { }
    
    public InvalidAgeException(string message) : base(message) { }
    
    public InvalidAgeException(string message, Exception inner) 
        : base(message, inner) { }
}

public class Person
{
    private int _age;
    
    public int Age
    {
        get => _age;
        set
        {
            if (value < 0 || value > 150)
                throw new InvalidAgeException($"Age must be between 0 and 150, got {value}");
            _age = value;
        }
    }
}

Exception Properties

csharp
try
{
    // Code that throws exception
}
catch (Exception ex)
{
    Console.WriteLine($"Message: {ex.Message}");
    Console.WriteLine($"Source: {ex.Source}");
    Console.WriteLine($"StackTrace: {ex.StackTrace}");
    Console.WriteLine($"HelpLink: {ex.HelpLink}");
    
    if (ex.InnerException != null)
    {
        Console.WriteLine($"Inner Exception: {ex.InnerException.Message}");
    }
}

Throwing Exceptions

csharp
public class BankAccount
{
    private decimal _balance;
    
    public void Withdraw(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentException("Amount must be positive", nameof(amount));
        
        if (amount > _balance)
            throw new InvalidOperationException($"Insufficient funds. Balance: {_balance}, Requested: {amount}");
        
        _balance -= amount;
    }
    
    public void Deposit(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentOutOfRangeException(nameof(amount), "Amount must be positive");
        
        _balance += amount;
    }
}

Exception Filters (C# 6.0+)

csharp
try
{
    // Code that might throw
}
catch (Exception ex) when (ex.Message.Contains("network"))
{
    Console.WriteLine("Network error occurred");
}
catch (Exception ex) when (ex.Message.Contains("database"))
{
    Console.WriteLine("Database error occurred");
}
catch (Exception ex)
{
    Console.WriteLine($"Other error: {ex.Message}");
}

Using Statement

csharp
public class FileProcessor
{
    public void ProcessFile(string filePath)
    {
        // Using statement ensures proper disposal
        using (StreamReader reader = new StreamReader(filePath))
        {
            string content = reader.ReadToEnd();
            Console.WriteLine(content);
        } // reader.Dispose() called automatically
    }
    
    // Alternative with using declaration (C# 8.0+)
    public void ProcessFileModern(string filePath)
    {
        using var reader = new StreamReader(filePath);
        string content = reader.ReadToEnd();
        Console.WriteLine(content);
    } // reader disposed at end of scope
}

Practical Examples

Safe Division

csharp
public class SafeMath
{
    public static double Divide(double numerator, double denominator)
    {
        try
        {
            return numerator / denominator;
        }
        catch (DivideByZeroException)
        {
            Console.WriteLine("Cannot divide by zero, returning 0");
            return 0;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Unexpected error in division: {ex.Message}");
            return double.NaN;
        }
    }
}

File Operations with Exception Handling

csharp
public class FileManager
{
    public string ReadFile(string filePath)
    {
        try
        {
            if (!File.Exists(filePath))
                throw new FileNotFoundException($"File not found: {filePath}");
            
            return File.ReadAllText(filePath);
        }
        catch (FileNotFoundException ex)
        {
            Console.WriteLine($"File not found: {ex.Message}");
            return string.Empty;
        }
        catch (UnauthorizedAccessException ex)
        {
            Console.WriteLine($"Access denied: {ex.Message}");
            return string.Empty;
        }
        catch (IOException ex)
        {
            Console.WriteLine($"IO error: {ex.Message}");
            return string.Empty;
        }
    }
    
    public bool WriteFile(string filePath, string content)
    {
        try
        {
            File.WriteAllText(filePath, content);
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Failed to write file: {ex.Message}");
            return false;
        }
    }
}

Database Operations

csharp
public class DatabaseManager
{
    public bool ExecuteQuery(string query)
    {
        try
        {
            // Simulate database operation
            if (string.IsNullOrWhiteSpace(query))
                throw new ArgumentException("Query cannot be empty");
            
            Console.WriteLine($"Executing: {query}");
            return true;
        }
        catch (SqlException ex)
        {
            Console.WriteLine($"Database error: {ex.Message}");
            return false;
        }
        catch (TimeoutException ex)
        {
            Console.WriteLine($"Query timeout: {ex.Message}");
            return false;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Unexpected error: {ex.Message}");
            return false;
        }
    }
}

Best Practices

Exception Handling Guidelines

csharp
// Good: Specific exception handling
try
{
    int.Parse(input);
}
catch (FormatException)
{
    Console.WriteLine("Invalid number format");
}

// Bad: Catching all exceptions
try
{
    int.Parse(input);
}
catch (Exception) // Too general
{
    Console.WriteLine("Something went wrong");
}

When to Throw vs Return

csharp
public class ValidationExample
{
    // Good: Throw for invalid state
    public void SetAge(int age)
    {
        if (age < 0 || age > 150)
            throw new ArgumentOutOfRangeException(nameof(age), "Age must be valid");
        
        // Set age...
    }
    
    // Good: Return for expected failure
    public bool TryParseAge(string input, out int age)
    {
        return int.TryParse(input, out age) && age >= 0 && age <= 150;
    }
}

Exception Logging

csharp
public class ExceptionLogger
{
    public static void LogException(Exception ex, string context = "")
    {
        string logMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] ";
        logMessage += $"Context: {context} | ";
        logMessage += $"Exception: {ex.GetType().Name} | ";
        logMessage += $"Message: {ex.Message} | ";
        logMessage += $"StackTrace: {ex.StackTrace}";
        
        Console.WriteLine(logMessage);
        
        // Could also write to file, database, etc.
    }
    
    public static T SafeExecute<T>(Func<T> operation, string context = "")
    {
        try
        {
            return operation();
        }
        catch (Exception ex)
        {
            LogException(ex, context);
            return default(T);
        }
    }
}

Summary

In this chapter, you learned:

  • Basic exception handling with try-catch-finally
  • Multiple catch blocks and exception hierarchy
  • Custom exception classes
  • Exception properties and throwing exceptions
  • Exception filters and using statements
  • Practical examples and best practices

Exception handling is crucial for creating robust, reliable applications that can gracefully handle errors and unexpected conditions.

Content is for learning and research only.