Create your own exception classes to represent domain-specific error conditions clearly.
public class InsufficientFundsException : Exception
{
public decimal Amount { get; }
public decimal Balance { get; }
public InsufficientFundsException(decimal amount, decimal balance)
: base($"Cannot withdraw {amount:C}. Balance is {balance:C}.")
{
Amount = amount;
Balance = balance;
}
}
public class BankAccount
{
private decimal _balance;
public BankAccount(decimal initial) => _balance = initial;
public void Withdraw(decimal amount)
{
if (amount > _balance)
throw new InsufficientFundsException(amount, _balance);
_balance -= amount;
}
}
var account = new BankAccount(100m);
try
{
account.Withdraw(200m);
}
catch (InsufficientFundsException ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine($"Tried: {ex.Amount:C}, Had: {ex.Balance:C}");
}
// Good practice: create a base exception for your domain
public class AppException : Exception
{
public AppException(string message) : base(message) { }
public AppException(string message, Exception inner) : base(message, inner) { }
}
public class ValidationException : AppException
{
public string Field { get; }
public ValidationException(string field, string message)
: base(message) => Field = field;
}