C# tutorials > Core C# Fundamentals > Exception Handling > How do you create and use custom exception types?
How do you create and use custom exception types?
Creating custom exception types in C# allows you to handle specific errors that are unique to your application or domain. This provides more clarity and control over error handling, making your code more robust and maintainable. This tutorial will walk you through the process of defining, throwing, and catching custom exceptions.
Defining a Custom Exception Class
To create a custom exception, you need to create a new class that inherits from the In the example above:System.Exception
class or one of its subclasses (e.g., System.ApplicationException
or System.SystemException
). It's generally recommended to inherit directly from System.Exception
. This class should include constructors to handle different scenarios, such as a default message, an inner exception, or custom data relevant to the exception.
InsufficientFundsException
is a custom exception class derived from Exception
.Balance
and WithdrawalAmount
to store relevant information about the error.ToString()
method for a more informative representation of the exception.
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, Exception innerException, decimal balance, decimal withdrawalAmount) : base(message, innerException)
{
Balance = balance;
WithdrawalAmount = withdrawalAmount;
}
public override string ToString()
{
return $"{Message}\nBalance: {Balance}\nWithdrawal Amount: {WithdrawalAmount}";
}
}
Throwing a Custom Exception
To raise or trigger a custom exception, use the In the example above:throw
keyword followed by an instance of your custom exception class. Include a meaningful message and any relevant data in the exception's constructor. This signals that an error has occurred and transfers control to the nearest exception handler.
Withdraw
method of the BankAccount
class checks if the withdrawal amount exceeds the balance.InsufficientFundsException
with a relevant message and the current balance and withdrawal amount.
public class BankAccount
{
private decimal _balance;
public BankAccount(decimal initialBalance)
{
_balance = initialBalance;
}
public void Withdraw(decimal amount)
{
if (amount > _balance)
{
throw new InsufficientFundsException("Insufficient funds for withdrawal.", _balance, amount);
}
_balance -= amount;
}
public decimal GetBalance()
{
return _balance;
}
}
Catching a Custom Exception
To handle a custom exception, use a In the example above:try-catch
block, specifically catching your custom exception type. This allows you to execute specific error handling logic based on the type of exception that occurred. It's good practice to also include a general catch
block (catch (Exception ex)
) to handle any unexpected exceptions.
try
block encloses the code that might throw an exception.catch (InsufficientFundsException ex)
block specifically catches the InsufficientFundsException
and handles it by printing the exception's details to the console.catch (Exception ex)
block catches any other exceptions that might occur.finally
block ensures that the message "Withdrawal attempt completed." is always printed, regardless of whether an exception was thrown or caught.
public class Example
{
public static void Main(string[] args)
{
BankAccount account = new BankAccount(100);
try
{
account.Withdraw(150);
}
catch (InsufficientFundsException ex)
{
Console.WriteLine(ex.ToString());
// Handle the exception appropriately, e.g., log the error, display a message to the user.
}
catch (Exception ex)
{
Console.WriteLine("An unexpected error occurred: " + ex.Message);
// Handle other exceptions.
}
finally
{
Console.WriteLine("Withdrawal attempt completed.");
}
}
}
Concepts Behind the Snippet
The core concepts behind custom exceptions are:
Exception
class, allowing them to be treated as general exceptions while retaining specific information.
Real-Life Use Case Section
Consider an e-commerce application. A custom exception like Another Example: A ProductOutOfStockException
could be used when a user tries to purchase a product that is no longer available. This allows the application to handle this specific error by displaying an appropriate message to the user and preventing the order from being processed.InvalidEmailFormatException
when validating user input.
Best Practices
Interview Tip
When discussing custom exceptions in an interview, be prepared to explain why they are useful, how to create them, and how they contribute to more robust and maintainable code. You should be able to describe scenarios where custom exceptions are beneficial and explain how to handle them properly.
When to Use Them
Use custom exceptions when:
Memory Footprint
Custom exceptions, like all objects in C#, consume memory. The memory footprint depends on the properties you include in your custom exception class. Avoid adding unnecessary data to the exception to minimize its memory usage. Keep in mind that frequent throwing and catching of exceptions can impact performance due to the overhead of stack unwinding and exception handling.
Alternatives
Alternatives to using custom exceptions include:
ArgumentException
or its derivatives (ArgumentNullException
, ArgumentOutOfRangeException
) might be sufficient.
Pros
Cons
FAQ
-
When should I use a custom exception instead of a built-in exception?
Use a custom exception when the error condition is specific to your application's domain and cannot be adequately represented by a built-in exception. This allows you to provide more context and handle the error more effectively. -
Should my custom exception inherit from
ApplicationException
orException
?
Inherit directly fromSystem.Exception
.ApplicationException
was intended to be the base class for application-specific exceptions, but this pattern is no longer recommended. Inheriting fromException
provides sufficient functionality and avoids potential confusion. -
How can I include additional information in my custom exception?
Add properties to your custom exception class to store relevant data about the error. Populate these properties in the exception's constructor and use them in your error handling logic.