Introduction
Exception handling in C# is a mechanism to handle runtime errors and maintain the normal flow of the application. C# provides a structured way to handle exceptions using try, catch, finally, and throw keywords. Proper exception handling ensures that your program can gracefully handle unexpected conditions and continue to operate or terminate cleanly.
Keywords Used in Exception Handling
- try: Encloses the block of code that might throw an exception.
- catch: Catches and handles exceptions thrown by the code inside the
tryblock. - finally: Executes a block of code regardless of whether an exception is thrown or not.
- throw: Used to explicitly throw an exception.
Basic Structure
try
{
// Code that might throw an exception
}
catch (ExceptionType e)
{
// Code to handle the exception
}
finally
{
// Code that runs regardless of an exception
}
Example: Basic Exception Handling
using System;
namespace ExceptionHandlingExample
{
class Program
{
static void Main(string[] args)
{
try
{
int a = 10;
int b = 0;
int result = a / b;
Console.WriteLine($"Result: {result}");
}
catch (DivideByZeroException ex)
{
Console.WriteLine("Exception caught: Division by zero is not allowed.");
Console.WriteLine($"Exception Message: {ex.Message}");
}
finally
{
Console.WriteLine("Execution of the finally block.");
}
}
}
}
Output
Exception caught: Division by zero is not allowed.
Exception Message: Attempted to divide by zero.
Execution of the finally block.
Multiple Catch Blocks
You can use multiple catch blocks to handle different types of exceptions.
Example
using System;
using System.IO;
namespace MultipleCatchExample
{
class Program
{
static void Main(string[] args)
{
try
{
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[5]);
string path = "nonexistentfile.txt";
string content = File.ReadAllText(path);
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine("Exception caught: Index out of range.");
Console.WriteLine($"Exception Message: {ex.Message}");
}
catch (FileNotFoundException ex)
{
Console.WriteLine("Exception caught: File not found.");
Console.WriteLine($"Exception Message: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine("Exception caught: General exception.");
Console.WriteLine($"Exception Message: {ex.Message}");
}
finally
{
Console.WriteLine("Execution of the finally block.");
}
}
}
}
Output
Exception caught: Index out of range.
Exception Message: Index was outside the bounds of the array.
Execution of the finally block.
Nested Try-Catch Blocks
You can nest try-catch blocks to handle exceptions in a more granular way.
Example
using System;
namespace NestedTryCatchExample
{
class Program
{
static void Main(string[] args)
{
try
{
try
{
int a = 10;
int b = 0;
int result = a / b;
Console.WriteLine($"Result: {result}");
}
catch (DivideByZeroException ex)
{
Console.WriteLine("Inner catch: Division by zero.");
}
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[5]);
}
catch (IndexOutOfRangeException ex)
{
Console.WriteLine("Outer catch: Index out of range.");
}
finally
{
Console.WriteLine("Execution of the finally block.");
}
}
}
}
Output
Inner catch: Division by zero.
Outer catch: Index out of range.
Execution of the finally block.
Throwing Exceptions
You can throw exceptions explicitly using the throw keyword.
Example
using System;
namespace ThrowExample
{
class Program
{
static void Main(string[] args)
{
try
{
ValidateAge(15);
}
catch (ArgumentOutOfRangeException ex)
{
Console.WriteLine($"Exception caught: {ex.Message}");
}
}
static void ValidateAge(int age)
{
if (age < 18)
{
throw new ArgumentOutOfRangeException("age", "Age must be at least 18.");
}
Console.WriteLine("Age is valid.");
}
}
}
Output
Exception caught: Age must be at least 18. (Parameter 'age')
Custom Exceptions
You can create custom exceptions by deriving from the Exception class.
Example
using System;
namespace CustomExceptionExample
{
class Program
{
static void Main(string[] args)
{
try
{
ValidateAge(15);
}
catch (InvalidAgeException ex)
{
Console.WriteLine($"Exception caught: {ex.Message}");
}
}
static void ValidateAge(int age)
{
if (age < 18)
{
throw new InvalidAgeException("Age must be at least 18.");
}
Console.WriteLine("Age is valid.");
}
}
// Custom exception class
public class InvalidAgeException : Exception
{
public InvalidAgeException(string message) : base(message)
{
}
}
}
Output
Exception caught: Age must be at least 18.
Best Practices for Exception Handling
- Use Specific Exceptions: Catch specific exceptions rather than using a general
Exceptioncatch block. - Do Not Swallow Exceptions: Avoid catching exceptions without handling them or logging them.
- Clean Up Resources: Use the
finallyblock to clean up resources like file handles, database connections, etc. - Log Exceptions: Always log exceptions to help with debugging and monitoring.
- Custom Exceptions: Create custom exceptions for application-specific error conditions.
Conclusion
Exception handling in C# is a robust feature that helps in managing runtime errors gracefully. By using try, catch, finally, and throw, you can ensure that your application can handle unexpected conditions and continue to operate or terminate cleanly. Proper exception handling is crucial for building reliable and maintainable applications.