Finally.... WHEN! (or exception filters)

Finally.... WHEN! (or exception filters)

With the introduction of c# 6 (no, not .net 6) the when keyword arrived... finally/luckily!

Why I am so happy about that? When we talk about using external ressources, we talk about exceptions which may happen... They can occure everywhere... for example reading a file, creating a connection and so on.

Before when

What I came accross in my developers life are the following examples:

// instead of multiple catch blocks for specific exceptions, just the Exception base class is catched
try { }
catch (Exception ex) {}

// sometimes afterwards filtered
try { }
catch (Exception ex) 
{
   if (ex.Message.Contains("...")) { }
   else throw;
}

// or filtering for some properties of the exception
catch (HttpRequestException exc) 
{
   if(exc.StatusCode is HttpStatusCode.BadGateway)
   { }
   else 
     throw;
}

Now catching the base class/general exception is bad practice or here.

The other problem is the stack unwinding, which is happening as soon as a catch block is entered. So every time an exception is not handled, but rethrown from the catch block, stack unwinding is happening, which will not only be done multiple times if the exception is rethrown, but you also loose your stack trace (beside you call another method again).

Using when

Using 'when', we can filter with any kind of bool logic without any stack unwinding happening:

catch (HttpRequestException exc) when (exc.StatusCode is HttpStatusCode.BadGateway)

Furthermore, we can easily improve code readability by combining catch blocks which do the same:

catch (UnauthorizedAccessException exc)
{
    return (false, exc.Message);
}
catch (SecurityException exc)
{
    return (false, exc.Message);
}
catch (IOException exc)
{
    return (false, exc.Message);
}

All three catch clauses do the same but instead of 4 lines we used 12. Now, using 'when' we can easily rewrite this to:

catch (Exception exc) when (exc is UnauthorizedAccessException or SecurityException or IOException)
{
    return (false, false, exc.Message);
}

If you require specific exception objects, eg. the Socket Errorcode, you still need to catch the SocketException itself.