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
try
block. - 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
Exception
catch block. - Do Not Swallow Exceptions: Avoid catching exceptions without handling them or logging them.
- Clean Up Resources: Use the
finally
block 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.