Fault
event handlers are one of the two handler types that aren’t available in C#. It behaves exactly like a finally
, except it is only run if control flow exits the block due to an exception being thrown.
As an example, take the following method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
.method public static void FaultExample(bool throwException) { .try { ldstr "Entering try block" call void [mscorlib]System.Console::WriteLine(string) ldarg.0 brfalse.s NormalReturn ThrowException: ldstr "Throwing exception" call void [mscorlib]System.Console::WriteLine(string) newobj void [mscorlib]System.Exception::.ctor() throw NormalReturn: ldstr "Leaving try block" call void [mscorlib]System.Console::WriteLine(string) leave.s Return } fault { ldstr "Fault handler" call void [mscorlib]System.Console::WriteLine(string) endfault } Return: ldstr "Returning from method" call void [mscorlib]System.Console::WriteLine(string) ret } |
If we pass true
to this method the following gets printed:
1 2 3 |
Entering try block Throwing exception Fault handler |
and the exception gets passed up the call stack. So, the exception gets thrown, the fault
handler gets run, and the exception propagates up the stack afterwards in the normal way.
If we pass false
, we get the following:
1 2 3 |
Entering try block Leaving try block Returning from method |
Because we are leaving the .try
using a leave.s
instruction, and not throwing an exception, the fault
handler does not get called.
Fault handlers and C#
So why were these not included in C#? It seems a pretty simple feature; one extra keyword that compiles in exactly the same way, and with the same semantics, as a finally
handler. If you think about it, the same behaviour can be replicated using a normal catch
block:
1 2 3 4 5 6 7 |
try { throw new Exception(); } catch { // fault code goes here throw; } |
The catch block only gets run if an exception is thrown, and the exception gets rethrown and propagates up the call stack afterwards; exactly like a fault
block. The only complications that occur is when you want to add a fault handler to a try block with existing catch handlers. Then, you either have to wrap the try
in another try
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
try { try { // ... } catch (DirectoryNotFoundException) { // ... // leave.s as normal... } catch (IOException) { // ... throw; } } catch { // fault logic throw; } |
or separate out the fault logic into another method and call that from the appropriate handlers:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
try { // ... } catch (DirectoryNotFoundException ) { // ... } catch (IOException ioe) { // ... HandleFaultLogic(); throw; } catch (Exception e) { HandleFaultLogic(); throw; } |
To be fair, the number of times that I would have found a fault
handler useful is minimal. Still, it’s quite annoying knowing such functionality exists, but you’re not able to access it from C#. Fortunately, there are some easy workarounds one can use instead.
Next time: filter handlers.
Load comments