What is an Exception?
An exception is an object that represents an error or unexpected event that occurs during the execution of a program. When an exception is thrown, the normal flow of the program is interrupted, and control is transferred to an appropriate exception handler.
Basic Exception Handling
In C#, exceptions are handled using try, catch, and finally blocks.
Try-Catch Block
The try block contains the code that may throw an exception. The catch block contains the code to handle the exception. If an exception occurs in the try block, control is transferred to the catch block.
try
{
// Code that may throw an exception
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[3]);
}
catch (IndexOutOfRangeException ex)
{
// Code to handle the exception
Console.WriteLine("An error occurred: " + ex.Message);
}
Finally Block
The final block contains code that is always executed, regardless of whether an exception is thrown. This is typically used for cleanup activities.
try
{
// Code that may throw an exception
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[3]);
}
catch (IndexOutOfRangeException ex)
{
// Code to handle the exception
Console.WriteLine("An error occurred: " + ex.Message);
}
finally
{
// Code that always executes
Console.WriteLine("Finally block executed.");
}
Multiple Catch Blocks
You can have multiple catch blocks to handle different types of exceptions separately.
try
{
// Code that may throw an exception
int number = int.Parse("abc");
}
catch (FormatException ex)
{
// Handle format exception
Console.WriteLine("Format exception: " + ex.Message);
}
catch (Exception ex)
{
// Handle any other exception
Console.WriteLine("An error occurred: " + ex.Message);
}
Catching All Exceptions
To catch all exceptions, you can use a general catch block that catches instances of the base Exception class. However, this should be used with caution as it can mask other issues.
try
{
// Code that may throw an exception
int number = int.Parse("abc");
}
catch (Exception ex)
{
// Handle any exception
Console.WriteLine("An error occurred: " + ex.Message);
}
Throwing Exceptions
You can throw exceptions using the throw keyword. This is useful for signaling errors from your methods.
public void ValidateAge(int age)
{
if (age < 0 || age > 120)
{
throw new ArgumentOutOfRangeException("age", "Age must be between 0 and 120.");
}
}
Custom Exceptions
You can define custom exception classes by inheriting them from the Exception class. This allows you to create exceptions that are specific to your application's domain.
public class InvalidAgeException : Exception
{
public InvalidAgeException(string message) : base(message) { }
}
// Using the custom exception
public void ValidateAge(int age)
{
if (age < 0 || age > 120)
{
throw new InvalidAgeException("Age must be between 0 and 120.");
}
}
Best Practices for Exception Handling
- Catch Specific Exceptions: Always catch specific exceptions rather than using a general catch block. This ensures that you handle each exception appropriately.
- Avoid Swallowing Exceptions: Do not catch exceptions without handling them. If you catch an exception, make sure to handle it or rethrow it.
- Use Finally for Cleanup: Use the finally block for cleanup activities such as closing files, releasing resources, etc.
- Provide Meaningful Messages: When throwing exceptions, provide meaningful error messages that help diagnose the issue.
- Log Exceptions: Always log exceptions to help with debugging and monitoring the health of your application.
- Do Not Use Exceptions for Flow Control: Avoid using exceptions to control the flow of your application. Use them for handling exceptional conditions only.
Conclusion
Exception handling is an essential part of developing reliable and maintainable C# applications. By using try, catch, and finally blocks effectively, you can ensure that your application can gracefully handle errors and continue to function correctly. Remember to follow best practices to provide meaningful error messages and ensure proper resource management.