- C# - Home
- C# - Overview
- C# - Environment
- C# - Program Structure
- C# - Basic Syntax
- C# - Data Types
- C# - Type Conversion
- C# - Variables
- C# - Constants
- C# - Operators
- C# - Arithmetic Operators
- C# - Assignment Operators
- C# - Relational Operators
- C# - Logical Operators
- C# - Bitwise Operators
- C# - Miscellaneous Operators
- C# - Operators Precedence
- C# Conditional Statements
- C# - Decision Making
- C# - If
- C# - If Else
- C# - Nested If
- C# - Switch
- C# - Nested Switch
- C# - Switch Expressions
- C# Control Statements
- C# - Loops
- C# - For Loop
- C# - While Loop
- C# - Do While Loop
- C# - Nested Loops
- C# - Break
- C# - Continue
- C# - Foreach Loop
- C# - Goto Statement
- C# OOP & Data Handling
- C# - Encapsulation
- C# - Methods
- C# - Nullables
- C# - Arrays
- C# - Strings
- C# - Structure
- C# - Enums
- C# - Classes
- C# - Inheritance
- C# - Polymorphism
- C# - Operator Overloading
- C# - Interfaces
- C# - Namespaces
- C# - Preprocessor Directives
- C# - Regular Expressions
- C# - Custom Exceptions
- C# - Exception Handling
- C# - File I/O
- C# Advanced Tutorial
- C# - Attributes
- C# - Reflection
- C# - Properties
- C# - Indexers
- C# - Delegates
- C# - Events
- C# - Collections
- C# - Generics
- C# - LINQ
- C# - IEnumerable vs IEnumerator
- C# - Anonymous Methods
- C# - Unsafe Codes
- C# - Tasks and Parallel Programming
- C# - Multithreading
- C# - Extension Methods
- C# - Lambda Expressions
- C# - Async and Await
- C# Modern Features
- C# - Tuples
- C# - Records
- C# - Pattern Matching Enhancements
- C# - Top-level Statements
- C# - Nullable Reference Types
- C# - What's New in C# 11 / 12 / 13
- C# - Global Usings
- C# - File-Scoped Namespaces
- C# Practical & Advanced Usage
- C# - JSON & XML Handling
- C# - Data Serialization & Deserialization
- C# - REST API Calls with Httpclient
- C# - Dependency Injection
- C# - Unit Testing with NUnit, xUnit & MSTest
- C# - Package Management with NuGet
Custom Exceptions in C#
In C# programming, an exception refers to an error that occurs during the execution of a program. However, in real-world applications, sometimes the built-in exceptions are not enough to clearly describe the problem; that is why we need to use custom exceptions. They are also called user-defined exceptions.
A custom exception allows us to define and manage application-specific errors in a clearer, more meaningful, and controlled way.
What is a Custom Exception in C#?
A custom exception is a user-defined class that inherits from the base System.Exception class (or a derived class). It enables developers to handle application-specific errors robustly and in a structured way.
How to Create a Custom Exception in C#
To create a custom exception class in C#, follow these steps −
- Create a new class that inherits from the Exception class.
- Define constructors (default, message-based, and with inner exception).
- Add custom properties or methods for additional information. It is optional.
- Use the try, catch and throw keywords to throw and catch the custom exception.
using System;
public class MyCustomException : Exception {
public MyCustomException() { }
public MyCustomException(string message)
: base(message) { }
public MyCustomException(string message, Exception innerException)
: base(message, innerException) { }
}
Why Use Custom Exceptions in C#?
We use custom exceptions to create our own exception classes that are helpful when you need to −
- Represent specific business logic errors (e.g., InvalidAge, UserNotFound, LowBalance).
- Make our exception handling more readable and organized.
- Add extra information like error codes, invalid values, or timestamps.
- Differentiate application errors from system errors.
- Provide a consistent exception structure across your application.
Example: Custom Exception in C#
In the following example, we create a user-defined exception for validating a person's age.
using System;
public class InvalidAgeException : Exception {
public InvalidAgeException(string message)
: base(message) { }
}
class Program {
static void ValidateAge(int age) {
if (age < 18){
throw new InvalidAgeException("Age must be 18 or older to register.");
}
Console.WriteLine("Registration successful!");
}
static void Main(){
try {
ValidateAge(15);
}
catch (InvalidAgeException ex) {
Console.WriteLine($"Custom Exception: {ex.Message}");
}
}
}
Following is the output −
Custom Exception: Age must be 18 or older to register.
Example: Adding Custom Properties to Exceptions
We can enhance our custom exception class by adding extra properties such as an error code or the invalid value.
using System;
public class InvalidAgeException : Exception {
public int AgeValue { get; }
// adding custom property
public InvalidAgeException(string message, int age)
: base(message) {
AgeValue = age;
}
}
class Program {
static void ValidateAge(int age) {
if (age < 18) {
throw new InvalidAgeException("You must be 18 or older.", age);
}
Console.WriteLine("Age is valid!");
}
static void Main() {
try {
ValidateAge(15);
}
catch (InvalidAgeException ex) {
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine($"Invalid Age Entered: {ex.AgeValue}");
}
}
}
Following is the output −
Error: You must be 18 or older. Invalid Age Entered: 15
C# Custom Exception with Inner Exception
In many situations, one exception can cause another. The InnerException property in C# helps you trace the original error that led to the current exception. It's useful for understanding the root cause of a problem while debugging.
using System;
public class FileProcessingException : Exception {
public FileProcessingException(string message, Exception inner) : base(message, inner) { }
}
class Program {
static void ProcessFile(){
try {
throw new NullReferenceException("File data is missing.");
}
catch (NullReferenceException ex) {
throw new FileProcessingException("Error while processing the file.", ex);
}
}
static void Main() {
try {
ProcessFile();
}
catch (FileProcessingException ex){
Console.WriteLine($"Custom Exception: {ex.Message}");
Console.WriteLine($"Inner Exception: {ex.InnerException.Message}");
}
}
}
Following is the output −
Custom Exception: Error while processing the file. Inner Exception: File data is missing.
Advantages of Custom Exceptions
Following are the advantages of custom exception −
- Provide clear and specific error messages.
- Help in better debugging and maintenance.
- Improve readability and structure of error-handling code.
- Allow custom logging and error reporting.
Buit-in Exception vs Custom Exception
Following is the difference between built-in and custom exceptions −
| Built-in Exceptions | Custom Exceptions |
|---|---|
| This is provided by .NET Framework (e.g., NullReferenceException, IndexOutOfRangeException). | It defined by the user for specific business rules or application needs. |
| It uses for General-purpose error handling. | It represents domain-specific error conditions. |
| It does not have extra properties after standard exception info. | It can include additional fields and methods. |
Conclusion
Custom exceptions in C# give us advantages to define meaningful, domain-specific errors that make our code cleaner, safer, and easy to debug. It is derived from the exception class, and by using it, we can build robust error-handling systems customized to our application's needs.