Introduction

This post is inspired by the book ‘C# in depth’ by Jon Skeet and presentation ‘Internals of Exceptions’ made by Adam Furmanek. The topic I want to focus on is stack unwinding when an exception is caught.

Problem

Let’s focus on the following code:

public void TestMethod()
{
  try
  {
    throw new InvalidOperationException("1");
  }
  finally
  {
    throw new IndexOutOfRangeException("2");
  }
}

public void CatchOnly(ILogger log)
{
  try
  {
    TestMethod();
  }
  catch (Exception e)
  {
    log.Log(e.StackTrace);
    throw;
  }
}

The problem you can notice while catching the exception is that you never catch InvalidOperationExcetpion in this construct. When you try to catch only InvalidOperationException it will not be caught either. Why? To enter exception block, the stack has to be unwound. The consequence is that all finally blocks must be called. So how can we log the fact that the primary exception was thrown.

Solution

The solution can sound like a workaround, but it bases on the fact, that exception filters do not unwind the stack while execution. The stack is unwound only when filter returns ‘true’ – we are going to enter exception catch block. But filter execution itself does not impact the stack.

public void CatchWithFilter(ILogger log)
{
  try
  {  
    TestMethod();
  }
  catch (Exception e) when (MyFilter(e, log))  
  {
    log.Log(e.StackTrace);    
    throw;
  }
}

public bool MyFilter(Exception e, ILogger log)
{
  log.Log(e.StackTrace);
  return true;
}

It means that ‘MyFilter’ method will be executed twice – first time for InvalidOperationException and second time for IndexOutOfRangeException. It is a very useful exception filters behavior when we want to diagnose what is the real cause of the failure. The real first thrown exception is caught.