'throw e;' vs. 'throw;'
Someone asked what the practical differences are between 'throw;' (no arguments) and 'throw object;' (in C# syntax).
Specifically, what's the difference between:
catch (Exception e)
{
throw;
}
and
catch (Exception e)
{
throw e;
}
This is mildly related to the 'catch' vs 'catch(Exception e)' vs. 'catch (SomeSpecificException e)'. I'll avoid talking about catch, and just focus on the rethrow.
What's the same:
Both throw an exception.
Both have the same debuggability problems associated with catch / rethrow.
They can be called in the same way. I used code like:
catch (Exception e) { if (...) throw; else throw e; }
as an academic way to demonstrate that they must have some similar properties. Never actually write code like that!
They can both be used in a naked catch block, although as difference #1 below mentions, 'throw e'; can't be used to rethrow the current exception.
catch
{
throw new MyWrapperException();
}
What's different:
- 'throw;' can only be used in the lexical scope of a catch block since it must gaurantee having a current exception. 'throw e' can be used anywhere.
- 'throw e' lets you provide a new exception object, such as a wrapper around the original exception.
- Only 'throw' can be used to rethrow the current exception within a naked catch block
- They both rethrow the current exception object, but “throw e;” resets parameters on it like the Exception.StackWalk property.
- They generate different IL opcodes. C#'s 'throw;' compiles to the 'rethrow' IL opcode, which doesn't take any parameters on the IL stack. 'throw e;' compiles to the 'throw' IL opcode, which takes 1 IL stack parameter: the exception to throw.
Check out the C# spec for more details
Comments
Anonymous
February 15, 2007
I use this as one of my interview questions. The most important difference in my mind is something you touched on, but did not make clear (IMO) In the throw e; syntax, the stack trace is reset to the current catch location, which could be significantly different from where the original exception was thrown. In the throw; syntax, the original stack trace is preserved, even if you have bubbled up several layers in the original call stack from where the exception is thrown. this is of course just a text representation, not the actual location in the call stack, which has already been unwound (as your "problems" article correctly reports.Anonymous
February 15, 2007
And please also add there common practice for wrapped rethrow: throw new MySpecialException("message",e); It is such a nightmare to debug code where exception's stack trace information is carefully cutted off. Please, do teach them to do it correct way, they listen to you.Anonymous
February 21, 2007
The comment has been removedAnonymous
February 21, 2007
C: This may do it: catch(TargetInvocationException e) { if (e.InnerException == null) throw; else throw e.InnerException; }Anonymous
February 21, 2007
The comment has been removedAnonymous
February 22, 2007
The comment has been removedAnonymous
February 22, 2007
C - unfortunately, any form of catch-rethrow is going to lose the stack, per issues here: http://blogs.msdn.com/jmstall/archive/2007/02/07/catch-rethrow.aspxAnonymous
February 22, 2007
Sam - I could imagine a good fxcop rule around this area, although it would require some good articulation skills to determine exactly what. However, I don't know if this usage pattern is common enough to make it a valuable rule.Anonymous
February 23, 2007
Hi Mike Turns out there is an fxcop rule already - It's called: "Rethrow to preserve stack details" The issue is pretty common: http://www.google.com/codesearch?hl=en&q=+lang:c%23+%22throw+e%3B%22&start=20&sa=NAnonymous
October 07, 2007
I just noticed that my blog had birthday #3 (Sep 30th) . In tradition, some various stats... 384 posts.