The for the last six1 releases the C# compiler has been keeping part of the .NET Framework secret from us2; exception filters. It turns out that the .NET Framework has supported exception filters since the very beginning, there was just no way to express them using C# until now.
C#6 adds the
when keyword for use in
catch blocks to specify exception filters. An exception filter is a predicate method that takes the thrown exception and returns
true when the exception should be caught or
false when it should not. If the filter says the exception should not be caught, the underlying system can continue to throw it.
This allows us to reduce the complexity in our code as we can put multiple
catch statements with different filtering rules in the same
catch block. This gives a
switch style approach to exception handling that is supported at the lowest level, reducing the need to rethrow exceptions (or to remember the difference between
Here is a
catch block showing an example of exception filtering:
Func<ArgumentException,string,bool> filterParameterName = (e,s) => e.ParamName == s;
CallSomething("param1", "param2", "param3", "param4");
catch (ArgumentException ex) when (ex.ParamName == "param1")
catch (ArgumentException ex) when (filterParameterName(ex, "param2"))
catch (ArgumentException ex)
Before I continue, I must state that this is a completely contrived example for demonstrable purposes; your filters would probably act on more than just the value of a string, the two filters shown would use the same code, and the handling would involve different things in each catch4.
Now, some things to note. First, the parentheses around the
when condition are mandatory; you don't need to remember this as the compiler and syntax highlighting will remind you. Second, the content of the
when condition must evaluate to
bool; you cannot specify a lambda expression here. I am certain most of you already assumed that, but for some reason, I felt like that should be possible. However,
when is akin to
while, so it makes sense that a lambda expression would not work.
The example above provides three different
catch blocks for the exact same exception type,
ArgumentException. Each filter is evaluated in the order specified, so, if
CallSomething() threw an
ParamName set to
when condition on the first
catch would reject it, but the second filter would catch it and handle accordingly. A
ParamName value filtered out of the first two
catch blocks would fall into the last.
Exception filtering is a useful and simple concept that should help to make exception handling easier to write. While some kind of filtering could be achieved before using conditions and
throw inside of
catch blocks, this language support now means that exception handlers (the content of
catch blocks) have a single responsibility and the
catch statements themselves are entirely responsible for declaring what must be caught. It also means that the exception handling within the .NET framework can be entirely responsible for routing exceptions in C#-implemented applications.
Exception filters have been supported by VB.NET and .NET-supporting variants of C++ since the versions released alongside .NET Framework 1.1; now, as of C#6, they are supported by C# too.