C# > Advanced C# > Exception Handling > Throwing Exceptions
Custom Exception with Contextual Information
This snippet demonstrates how to create and throw a custom exception with additional information, providing better context for debugging and handling specific error scenarios.
Defining a Custom Exception
This code defines a custom exception class `InsufficientFundsException` that inherits from the base `Exception` class. It includes additional properties, `Balance` and `WithdrawalAmount`, to store relevant information about the failed operation. The constructor takes a message, balance, and withdrawal amount, allowing you to initialize the exception with specific details. It also allows for an optional inner exception for wrapping other exceptions.
using System;
public class InsufficientFundsException : Exception
{
public decimal Balance { get; private set; }
public decimal WithdrawalAmount { get; private set; }
public InsufficientFundsException(string message, decimal balance, decimal withdrawalAmount) : base(message)
{
Balance = balance;
WithdrawalAmount = withdrawalAmount;
}
public InsufficientFundsException(string message, decimal balance, decimal withdrawalAmount, Exception innerException) : base(message, innerException)
{
Balance = balance;
WithdrawalAmount = withdrawalAmount;
}
public override string ToString()
{
return $"{base.ToString()}\n Balance: {Balance}\n Withdrawal Amount: {WithdrawalAmount}";
}
}
Throwing the Custom Exception
This code demonstrates how to throw the `InsufficientFundsException` when a withdrawal attempt exceeds the account balance. The `Withdraw` method checks if the withdrawal amount is greater than the balance, and if so, throws the custom exception, including the current balance and the attempted withdrawal amount. The `Main` method includes a try-catch block to handle the exception.
using System;
public class BankAccount
{
private decimal _balance;
public BankAccount(decimal initialBalance)
{
_balance = initialBalance;
}
public void Withdraw(decimal amount)
{
if (amount > _balance)
{
throw new InsufficientFundsException("Withdrawal amount exceeds balance.", _balance, amount);
}
_balance -= amount;
}
public decimal GetBalance()
{
return _balance;
}
}
public class Example
{
public static void Main(string[] args)
{
BankAccount account = new BankAccount(100.00m);
try
{
account.Withdraw(150.00m);
}
catch (InsufficientFundsException ex)
{
Console.WriteLine(ex);
// Handle the exception appropriately (e.g., log it, inform the user)
}
catch (Exception ex)
{
Console.WriteLine("An unexpected error occurred: " + ex.Message);
}
}
}
Concepts Behind the Snippet
This snippet uses the principles of object-oriented programming, especially exception handling and custom exception creation. It allows for a more specific way to handle exceptions that can occur in certain situations, like withdrawing from a bank account. Exceptions are derived from a base `Exception` class. Custom exceptions allow the passing of contextual information for richer debugging and handling.
Real-Life Use Case
Imagine an e-commerce system. You could have a `ProductOutOfStockException` when a user tries to purchase a product that is no longer available, including information about the product ID and the requested quantity. This allows the system to handle the error gracefully, informing the user and potentially suggesting alternatives.
Best Practices
Interview Tip
Be prepared to discuss the benefits of custom exceptions over using generic exceptions. Highlight the increased clarity and context they provide, and their contribution to more robust and maintainable code. Understand the exception hierarchy and how to best leverage existing exception types.
When to Use Them
Use custom exceptions when you need to handle errors that are specific to your application or domain. This allows you to write more targeted error handling logic and provide more informative error messages to users and developers. Avoid creating custom exceptions for common error scenarios that are already covered by standard .NET exceptions (e.g., `ArgumentNullException`, `InvalidOperationException`).
Memory Footprint
Creating custom exceptions doesn't inherently introduce a significant memory overhead. The memory footprint of an exception is primarily determined by the amount of information it stores (e.g., the message, stack trace, and any additional properties). Be mindful of the data you include in your custom exceptions, and avoid storing large or unnecessary objects.
Alternatives
While custom exceptions are powerful, consider these alternatives:
Pros
Cons
FAQ
-
When should I throw an exception instead of returning an error code?
Throw exceptions for exceptional situations that the calling code cannot reasonably be expected to handle. Use error codes or result objects for more routine errors that the calling code should handle directly. -
Can I catch multiple exception types in a single catch block?
Yes, you can catch multiple exception types in a single catch block using exception filters (the `when` keyword in C#). You can also have multiple catch blocks to handle different exception types separately.