- 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.