3

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!

Cyrus
  • 2,261
  • 2
  • 22
  • 37
  • 3
    No, you can't. Exception 1 was discarded when Exception 2 was thrown. – iakobski Aug 18 '19 at 11:37
  • Why do you want to throw an exception in `finally`? It seems strange that you would have a method you always want to fail. – ProgrammingLlama Aug 18 '19 at 11:39
  • @John The `FixedUnalterableMethod` method is in external dll, and I can't change it. But I would like to know that the `Exception 1` has occurred. – Cyrus Aug 18 '19 at 11:42

3 Answers3

12

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);
    }
}
Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
  • 3
    This is fantastic! A lovely little nugget of almost-always-useless but fascinating information – canton7 Aug 18 '19 at 13:44
  • 1
    Very interesting, always amazing to find language features like this. Thanks for the detailed explanation! – Eric S Aug 19 '19 at 15:02
0

If the "exception type" is literally the same you probably have little choice but the examine the Message property, which can be problematic to say the least.

Looking at that code again you will only ever see the 1 exception anyway, the one on line 16.

Paul Kohler
  • 2,684
  • 18
  • 31
0

Thanks to @Daniel Earwicker the working solution is:

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

void Method1()
{
    bool CatchException(Exception ex)
    {
        //Log...

        Console.WriteLine(ex.ToString());
        return true;
    }

    try
    {
        FixedUnalterableMethod(); //line 24.
    }
    catch (Exception ex) when (CatchException(ex))
    {
        //do something with the lastest exception
    }
}
Cyrus
  • 2,261
  • 2
  • 22
  • 37