C# - Exception Handling


Exception handling in C# allows you to gracefully handle runtime errors and unexpected situations that may occur during the execution of your program. The primary mechanism for exception handling in C# is the use of try, catch, finally, and throw keywords.

Here's a basic overview of exception handling in C#:

try, catch, finally Blocks:

  • The try block contains the code where an exception might occur.
  • The catch block catches and handles exceptions that occur in the try block.
  • The finally block (optional) contains code that will always be executed, whether an exception occurred or not.
try
{
    // Code that may throw an exception
}
catch (ExceptionType1 ex1)
{
    // Handle exceptions of type ExceptionType1
}
catch (ExceptionType2 ex2)
{
    // Handle exceptions of type ExceptionType2
}
finally
{
    // Code that always executes, whether an exception occurred or not
}

throw Statement:

  • The throw statement is used to manually throw an exception.
  • You can throw built-in exceptions or create custom exceptions by deriving from the Exception class.
try
{
    // Code that may throw an exception
    if (someCondition)
    {
        throw new CustomException("An error occurred!");
    }
}
catch (CustomException ex)
{
    // Handle the custom exception
    Console.WriteLine($"Custom Exception: {ex.Message}");
}

Exception Types:

C# has a hierarchy of exception classes derived from the System.Exception class. Common exception types include System.Exception, System.ArgumentException, System.NullReferenceException, etc.

Exception Filters (C# 6.0 and later):

C# 6.0 introduced exception filters, allowing you to catch exceptions based on a condition. This can be useful when you want to catch only certain exceptions that meet specific criteria.

try
{
    // Code that may throw an exception
}
catch (Exception ex) when (ex.Message.Contains("specific condition"))
{
    // Handle exceptions that meet the condition
}

Handling Unhandled Exceptions:

You can subscribe to the AppDomain.UnhandledException event to handle unhandled exceptions at the application level.

static void Main()
{
    AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
    {
        Exception e = (Exception)args.ExceptionObject;
        Console.WriteLine($"Unhandled Exception: {e.Message}");
    };

    // Rest of the application code
}

Custom Exception Classes:

You can create custom exception classes by deriving from System.Exception. This allows you to provide additional information about the exception and create a more meaningful exception hierarchy for your application.

[Serializable]
public class CustomException : Exception
{
    public CustomException() { }
    public CustomException(string message) : base(message) { }
    public CustomException(string message, Exception inner) : base(message, inner) { }
    protected CustomException(
      System.Runtime.Serialization.SerializationInfo info,
      System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}

Exception handling is essential for writing robust and reliable code. It helps prevent crashes and provides a mechanism for handling errors in a controlled manner. Always try to catch only the specific exceptions that you can handle, and let the others propagate up the call stack or log them for further analysis.