C# – Catching exceptions with “catch, when”

cexception handling

I came across this new feature in C# which allows a catch handler to execute when a specific condition is met.

int i = 0;
try
{
    throw new ArgumentNullException(nameof(i));
}
catch (ArgumentNullException e)
when (i == 1)
{
    Console.WriteLine("Caught Argument Null Exception");
}

I am trying to understand when this may ever be useful.

One scenario could be something like this:

try
{
    DatabaseUpdate()
}
catch (SQLException e)
when (driver == "MySQL")
{
    //MySQL specific error handling and wrapping up the exception
}
catch (SQLException e)
when (driver == "Oracle")
{
    //Oracle specific error handling and wrapping up of exception
}
..

but this is again something that I can do within the same handler and delegate to different methods depending on the type of the driver. Does this make the code easier to understand? Arguably no.

Another scenario that I can think of is something like:

try
{
    SomeOperation();
}
catch(SomeException e)
when (Condition == true)
{
    //some specific error handling that this layer can handle
}
catch (Exception e) //catchall
{
    throw;
}

Again this is something that I can do like:

try
{
    SomeOperation();
}
catch(SomeException e)
{
    if (condition == true)
    {
        //some specific error handling that this layer can handle
    }
    else
        throw;
}

Does using the 'catch, when' feature make exception handling faster because the handler is skipped as such and the stack unwinding can happen much earlier as when compared to handling the specific use cases within the handler? Are there any specific use cases that fit this feature better which people can then adopt as a good practice?

Best Answer

Catch blocks already allow you to filter on the type of the exception:

catch (SomeSpecificExceptionType e) {...}

The when clause allows you to extend this filter to generic expressions.

Thus, you use the when clause for cases where the type of the exception is not distinct enough to determine whether the exception should be handled here or not.


A common use case are exception types which are actually a wrapper for multiple, different kinds of errors.

Here's a case that I've actually used (in VB, which already has this feature for quite some time):

try
{
    SomeLegacyComOperation();
}
catch (COMException e) when (e.ErrorCode == 0x1234)
{
    // Handle the *specific* error I was expecting. 
}

Same for SqlException, which also has an ErrorCode property. The alternative would be something like that:

try
{
    SomeLegacyComOperation();
}
catch (COMException e)
{
    if (e.ErrorCode == 0x1234)
    {
        // Handle error
    }
    else
    {
        throw;
    }
}

which is arguably less elegant and slightly breaks the stack trace.

In addition, you can mention the same type of exception twice in the same try-catch-block:

try
{
    SomeLegacyComOperation();
}
catch (COMException e) when (e.ErrorCode == 0x1234)
{
    ...
}
catch (COMException e) when (e.ErrorCode == 0x5678)
{
    ...
}

which would not be possible without the when condition.