Search code examples
c#.netexceptiontry-catchtry-finally

in C# try-finally how to catch the original exception


My simple example is:

    void FixedUnalterableMethod()
    {
        try
        {
            throw new Exception("Exception 1"); //line 12.
        }
        finally
        {
            throw new Exception("Exception 2"); //line 16.
        }
    }

    void Method1()
    {
        try
        {
            FixedUnalterableMethod(); //line 24.
        }
        catch (Exception ex)
        {
            var messageWithStackTrace = ex.ToString(); //line 28.
            Console.WriteLine(messageWithStackTrace);
        }
    }

The console output is:

System.Exception: Exception 2
    at Program.FixedUnalterableMethod() in ...\Program.cs:line 16
    at Program.Main(String[] args) in ...\Program.cs:line 24

The question is, how to be informed that the Exception 1 has occured? Is there a way how to include Exception 1 in my StackTrace (in line 28.) ?

Of coure I can't modify the FixedUnalterableMethod() method!


Solution

  • Yes, this is possible, though pretty nasty!

    It is a little known fact that CLR exceptions do not cause the execution of finally blocks until the exception has actually been caught. This is disguised somewhat because if an exception is not caught (and makes it out of Main) then the default behaviour of the CLR hosting code is to run finally blocks for you, giving the illusion that they always run.

    However, there is a way to examine an exception before catching it, to decide if you want to catch it. Try this:

    static bool StoreFirstException(Exception x, Action<Exception> store)
    {
        if (x.Message == "Exception 1")
        {
            store(x);                
        }
    
        return true;
    }
    
    static void Method1()
    {
        Exception firstException = null;
    
        try
        {
            FixedUnalterableMethod(); //line 24.
        }
        catch (Exception ex) when (StoreFirstException(ex, x => firstException = x))
        {
            Console.WriteLine(firstException);               
            Console.WriteLine(ex);
        }
    }
    

    The catch... when feature lets you write a boolean expression to examine the exception. Here I check the message (the only distinguishing fact you've given me) and if it's the first exception I pass it to the store action.

    The caller uses this callback to stash the first exception.

    Then it votes to catch, which only then causes the finally block to execute, which throws the second exception. The same when clause examines it but this time doesn't offer it to store. So then I have both exceptions in the catch block and I log them both. My console shows the two exceptions with the correct source line numbers.

    Here's version that doesn't look at the message; it just assumes the first exception it see must be the interesting one. Also it's neater to use a nested function:

    static void Method1()
    {
        Exception firstException = null;
    
        bool StoreFirstException(Exception x)
        {
            if (firstException == null) firstException = x;
            return true;
        }
    
        try
        {
            FixedUnalterableMethod(); //line 24.
        }
        catch (Exception ex) when (StoreFirstException(ex))
        {
            Console.WriteLine(firstException);               
            Console.WriteLine(ex);
        }
    }