Rethrowing an exception and preserving stack trace

  • Thread starter =?ISO-8859-1?Q?Lasse_V=E5gs=E6ther_Karlsen?=
  • Start date
?

=?ISO-8859-1?Q?Lasse_V=E5gs=E6ther_Karlsen?=

If I got the following code:

try
{
// something that might throw an exception
}
catch (Exception ex)
{
// Log contents of ex here
throw;
}

this will rethrow the exception after logging it, however the stack
trace from there on will show the line of the "throw;" statement as the
first entry. If I drop the try/catch block here then the actual line of
code throwing the exception will be the first entry.

Using either "throw;" or "throw ex;" produces the same result, the
existing stack trace gets replaced with a new one starting with the
re-throwing statement.

Is there a way to fix this? Can I do something that will keep the
existing stack trace? Wether the re-throwing statement line and file
gets added to the stack trace or not is not important, I just don't want
to loose the history from the stack trace to that point.

Throwing a new exception and using the previous one as an InnerException
does not change it as only the new exceptions stack trace is reset,
however it seems a bit awkward to do this all over:

throw new SomeExceptionHere(ex.Message, ex);

just to keep the stack trace, and of course I would have to unwind the
tree of exceptions later on to rebuild the full stack trace anyway.
 
J

Jon Skeet [C# MVP]

Lasse said:
If I got the following code:

try
{
// something that might throw an exception
}
catch (Exception ex)
{
// Log contents of ex here
throw;
}

this will rethrow the exception after logging it, however the stack
trace from there on will show the line of the "throw;" statement as the
first entry. If I drop the try/catch block here then the actual line of
code throwing the exception will be the first entry.

Using either "throw;" or "throw ex;" produces the same result, the
existing stack trace gets replaced with a new one starting with the
re-throwing statement.

No - using throw; should be okay, but using throw ex; replaces the
stack trace.

Here's an example:

using System;
using System.Runtime.CompilerServices;

class Test
{
[MethodImpl(MethodImplOptions.NoInlining)]
static void InnerCall()
{
throw new Exception();
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void OuterCall()
{
try
{
InnerCall();
}
catch
{
throw;
}
}


static void Main()
{
try
{
OuterCall();
}
catch (Exception e)
{
Console.WriteLine (e);
}
}
}

Output is:
System.Exception: Exception of type 'System.Exception' was thrown.
at Test.InnerCall()
at Test.OuterCall()
at Test.Main()

Changing the "throw;" to "throw ex;" (declaring the exception of
course) changes the output to:

System.Exception: Exception of type 'System.Exception' was thrown.
at Test.OuterCall()
at Test.Main()

I've included some attributes to ensure the JIT doesn't inline things.
They don't appear to make a difference in this case, but inlining may
explain why you've seen it not work in the past.

Jon
 
?

=?ISO-8859-1?Q?Lasse_V=E5gs=E6ther_Karlsen?=

Jon said:
Lasse Vågsæther Karlsen wrote:

Changing the "throw;" to "throw ex;" (declaring the exception of
course) changes the output to:

System.Exception: Exception of type 'System.Exception' was thrown.
at Test.OuterCall()
at Test.Main()

I've included some attributes to ensure the JIT doesn't inline things.
They don't appear to make a difference in this case, but inlining may
explain why you've seen it not work in the past.

Jon

Thanks, I notice the same when I add the attributes, so then I know what
it is.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top