Собственное исключение (Custom Exception) в C#

Создание собственных исключений в C# оправдано, когда стандартных типов исключений недостаточно для точного описания ошибки. Это позволяет сделать код более читаемым, предоставляя дополнительную информацию об ошибке и упрощая её обработку.

Когда стоит использовать собственные исключения

  1. Отражение специфики доменной области — стандартные исключения могут быть недостаточно информативными в контексте конкретной предметной области.
  2. Необходимость передачи дополнительных данных — собственные исключения позволяют добавлять свойства, содержащие дополнительную информацию об ошибке.
  3. Повторное использование иерархии ошибок — если нужно создавать единую систему обработки ошибок, собственные исключения помогают классифицировать ошибки внутри приложения.
  4. Упрощение отладки — специфические исключения облегчают отладку, так как они четко указывают на источник проблемы.

Как создать собственное исключение

Рассмотрим более реальный пример. Предположим, в банковском приложении требуется обработка ситуации, когда на счете недостаточно средств для выполнения операции.

using System;

class InsufficientFundsException : Exception
{
    public decimal CurrentBalance { get; }
    public decimal WithdrawAmount { get; }
    
    public InsufficientFundsException(string message, decimal currentBalance, decimal withdrawAmount) 
        : base(message)
    {
        CurrentBalance = currentBalance;
        WithdrawAmount = withdrawAmount;
    }
}

class BankAccount
{
    public decimal Balance { get; private set; }
    
    public BankAccount(decimal initialBalance)
    {
        Balance = initialBalance;
    }
    
    public void Withdraw(decimal amount)
    {
        if (amount > Balance)
        {
            throw new InsufficientFundsException("Недостаточно средств на счете", Balance, amount);
        }
        Balance -= amount;
    }
}

class Program
{
    static void Main()
    {
        var account = new BankAccount(500);
        try
        {
            account.Withdraw(1000);
        }
        catch (InsufficientFundsException ex)
        {
            Console.WriteLine($"Ошибка: {ex.Message}");
            Console.WriteLine($"Баланс: {ex.CurrentBalance}, Запрошено: {ex.WithdrawAmount}");
        }
    }
}

Вывод:

Ошибка: Недостаточно средств на счете
Баланс: 500, Запрошено: 1000

Наследование собственных исключений

Можно создавать иерархию исключений, чтобы лучше классифицировать ошибки в системе.

using System;

class BankingException : Exception
{
    public BankingException(string message) : base(message) { }
}

class OverdraftException : BankingException
{
    public OverdraftException(string message) : base(message) { }
}

class Program
{
    static void Main()
    {
        try
        {
            throw new OverdraftException("Превышен лимит овердрафта");
        }
        catch (BankingException ex)
        {
            Console.WriteLine($"Ошибка банковской системы: {ex.Message}");
        }
    }
}

Вывод:

Ошибка банковской системы: Превышен лимит овердрафта

Создание собственных исключений в C# позволяет сделать код более выразительным, улучшить обработку ошибок и упростить поддержку приложения.