.NET

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.

    Danilo Cavalcante

    Working with web development since 2005, currently as a senior programmer analyst. Development, maintenance, and integration of systems in C#, ASP.Net, ASP.Net MVC, .Net Core, Web API, WebService, Integrations (SOAP and REST), Object-Oriented Programming, DDD, SQL, Git, and JavaScript

    Recent Posts

    Encapsulation and Abstraction in C#

    Encapsulation and abstraction are two pillars of object-oriented programming (OOP) that play a vital role…

    4 weeks ago

    Polymorphism in C#: Object-Oriented Programming

    Polymorphism is a fundamental concept in object-oriented programming (OOP) that allows objects to take on…

    4 weeks ago

    Understanding Inheritance in C#

    Inheritance is a cornerstone of object-oriented programming (OOP) and one of its most powerful features.…

    4 weeks ago

    Classes and Objects in C#: Object-Oriented Programming

    In the world of C# and object-oriented programming (OOP), classes and objects form the backbone…

    1 month ago

    Collections and LINQ Queries in C#

    In modern C# programming, working with data collections is a common task. Understanding how to…

    1 month ago

    Do Docker Containers Take Up Space?

    One of the common questions among Docker users is whether Docker containers consume disk space.…

    7 months ago