Filtering try-catch statement

Apply filtering to catch statements with a when clause

Home DailyDrop

Daily Knowledge Drop

It is possible to filter the catch portion of the try-catch statement, as well as catch multiple exceptions at the same time using the C# when keyword.


Multiple exceptions

In our use case, there are two exception types we are particularly interested in IndexOutOfRangeException and DivideByZeroException.
If either of these exceptions occur, we want to log the exception, and carry on with the workflow. However if any other exception occurs, it should be logged and re-thrown to be handled higher up the call stack.

Multiple catch

Usually this would be done with multiple catch statements:

try
{
    // array only has 2 elements
    var array = new int[2];
    // trying to access 3rd element. not allowed
    // this will be caught by the first catch statement
    array[3] = 100;
}
catch (IndexOutOfRangeException ex) 
{
    Console.WriteLine("Caught IndexOutOfRangeException: Log and ignore" );
}
catch (DivideByZeroException ex)
{
    Console.WriteLine("Caught DivideByZeroException: Log and ignore");
}
catch (Exception ex)
{
    Console.WriteLine("Caught all other exceptions: Log and throw");
    throw;
}

Here there are three different catch statements each handling a different type of exception. However for the first two types of exception, the same logic needs to take place, so lets group these two exceptions together.


When clause

The when clause can be used to group multiple exceptions together:

try
{
    // divide by zero. not allow
    // this will be caught by the first catch statement
    // along with any IndexOutOfRange exceptions
    var zero = 0;
    var value = 100 / zero;
}
catch (Exception ex) when (ex is IndexOutOfRangeException ||
                            ex is DivideByZeroException)
{
    Console.WriteLine("Caught IndexOutOfRangeException or " +
        "DivideByZeroException: Log and ignore");
}
catch (Exception ex)
{
    Console.WriteLine("Caught all other exceptions: Log and throw");
    throw;
}

The type of the exception being caught is checked. If the exception type is one of the two we are interested in, the first catch block is entered, otherwise the exception falls through to the second catch block.


Exception filtering

In our use case, we have defined a custom exception, with a Status field. Based on the value of the Status field, one of three things should happen:

  • log the exception
  • log and re-thrown the exception
  • ignore the exception.

Switch

Usually for filtering a switch could be done within the catch statement:

try
{
    throw new StatusException(3);
}
catch (StatusException ex)
{
    switch (ex.Status)
    {
        case 0:
        case 1:
            Console.WriteLine($"Logging exception with status: {ex.Status}");
            Console.WriteLine(ex.Message);
            break;
        case 3:
        case 5:
            Console.WriteLine($"Ignoring exception with status: {ex.Status}");
            break;
        default:
            Console.WriteLine($"Throwing exception with status: {ex.Status}");
            throw;
    }
}

class StatusException : Exception
{
    public int Status;

    public StatusException(int status)
    {
        Status = status;
    }
}

The when clause can also be used to filter the catch statement, based on properties of the exception.

When clause

Below we are filtering which catch block should handling the exception based on the Status field value:

try
{
    throw new StatusException(1);
}
catch (StatusException ex) when (ex.Status == 0 || ex.Status == 1)
{
    Console.WriteLine($"Logging exception with status: {ex.Status}");
    Console.WriteLine(ex.Message);
}
catch (StatusException ex) when (ex.Status == 3 || ex.Status == 5)
{
    Console.WriteLine($"Ignoring exception with status: {ex.Status}");
}
catch (StatusException ex)
{
    Console.WriteLine($"Throwing exception with status: {ex.Status}");
    throw;
}

class StatusException : Exception
{
    public int Status;

    public StatusException(int status)
    {
        Status = status;
    }
}

Conclusion

The when clause is a useful addition to the existing techniques to handle multiple exceptions and allow for decision making based on exception values.


References

Catch Multiple Exceptions in C#

Daily Drop 10: 14-02-2022

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net exception when filter