Exception Handling in C#: try-catch, finally, and Custom Exceptions

Exception handling is a critical part of writing robust and maintainable C# applications. It allows developers to anticipate, detect, and gracefully recover from errors that may occur during program execution. This blog post will cover the basics of exception handling in C#, including the try-catch mechanism, the use of finally blocks, and creating custom exceptions.

What is Exception Handling?

In programming, exceptions are unexpected events or errors that disrupt the normal flow of a program. Examples include accessing a null object, dividing by zero, or encountering a file not found error. Exception handling enables developers to manage these situations effectively, ensuring the application remains stable and provides meaningful feedback to users.

Key Components of Exception Handling

1. try-catch Block

The try block contains the code that might throw an exception, while the catch block handles the exception if it occurs.

Syntax:

try
{
    // Code that might throw an exception
}
catch (ExceptionType e)
{
    // Code to handle the exception
}

Example

try
{
    int numerator = 10;
    int denominator = 0;
    int result = numerator / denominator; // This will throw a DivideByZeroException
}
catch (DivideByZeroException ex)
{
    Console.WriteLine($"Error: {ex.Message}");
}

2. The finally Block

The finally block contains code that will always execute, regardless of whether an exception is thrown or not. It is typically used for cleanup operations like closing files, releasing resources, or resetting states.

Syntax:

try
{
    // Code that might throw an exception
}
catch (ExceptionType e)
{
    // Code to handle the exception
}
finally
{
    // Code that always executes
}

Example

StreamReader reader = null;
try
{
    reader = new StreamReader("file.txt");
    string content = reader.ReadToEnd();
    Console.WriteLine(content);
}
catch (FileNotFoundException ex)
{
    Console.WriteLine("File not found.");
}
finally
{
    reader?.Close(); // Ensure the file is closed, even if an exception occurs
}

3. Custom Exceptions

Custom exceptions allow developers to create meaningful error messages tailored to their application’s domain. Custom exceptions must inherit from the base System.Exception class.

Creating a Custom Exception:

public class InvalidAgeException : Exception
{
    public InvalidAgeException(string message) : base(message)
    {
    }
}

Using the Custom Exception:

public void ValidateAge(int age)
{
    if (age < 18)
    {
        throw new InvalidAgeException("Age must be 18 or older.");
    }
}

try
{
    ValidateAge(16);
}
catch (InvalidAgeException ex)
{
    Console.WriteLine($"Validation Error: {ex.Message}");
}

Best Practices for Exception Handling

Catch Specific Exceptions: Always catch specific exceptions rather than the generic Exception class to avoid masking unexpected issues.

    try
    {
        // Code
    }
    catch (ArgumentNullException ex)
    {
        // Handle ArgumentNullException
    }
    catch (InvalidOperationException ex)
    {
        // Handle InvalidOperationException
    }
    

    Avoid Empty Catch Blocks: Always provide meaningful error handling. Empty catch blocks can make debugging difficult.

    catch (Exception ex)
    {
        Console.WriteLine($"Error: {ex.Message}");
    }
    

    Use finally for Cleanup: Always close resources like files or database connections in the finally block.

    Avoid Overusing Exceptions: Exceptions should be used for exceptional scenarios, not as a control flow mechanism

    Conclusion

    Exception handling is a powerful tool that ensures your applications can gracefully handle unexpected situations. By mastering the try-catch block, understanding the role of finally, and creating meaningful custom exceptions, you can write robust and user-friendly applications.

    3 responses to “Exception Handling in C#: try-catch, finally, and Custom Exceptions”

    1. John Avatar
      John

      VWwhhv HXx aSlcB

    2. levitra vendita online Avatar
      levitra vendita online

      Thanks for sharing your experience. We hit a similar bottleneck and solved it by implementing response caching with OutputCache middleware in .NET 8. The performance gains were significant for our read-heavy endpoints.

    3. Alanna1174 Avatar
      Alanna1174

      Insightful read. We recently containerized a legacy .NET Framework app using Windows containers and the migration was smoother than expected. Docker Compose made the local dev experience much better.

    Leave a Reply

    Your email address will not be published. Required fields are marked *


    Categories


    Tag Cloud

    .net algorithms angular api Array arrays async asynchronous basic-concepts big o blazor c# classes code components containers control-structures csharp data structures Deep Learning dictionaries docker dom dotnet framework functions guide javascript json leetcode linq lists LLM loops methods Natural Language Processing npm object oriented programming oop operators promisses Python tutorial variables web framework