2

I've got it in my head that throwing an exception has side effects (like collecting stack information), but I'm realizing it might not. Is there a difference between the following two versions of GetException?

public Exception GetException() {
    try {
        throw new Exception("Bummer");
    }
    catch (Exception e) {
        return e;
    }
}

public Exception GetException() {
    return new Exception("Bummer");
}
Chris Pfohl
  • 18,220
  • 9
  • 68
  • 111

2 Answers2

3

When an exception is thrown, the stack trace is "inserted" into the exception (that is what you can get through the StackTrace property). So yes, there is a side-effect in throwing an exception object.

A problem of rethrowing an exception (even with

throw;

is that the stack trace is mangled (or even overwritten, if you use throw ex;))

Note that throw; is better than throw ex;, because the first one will only mangle a little the line numbers, while the later will reset totally the stack trace.

There are some persons that don't trust... Look at https://dotnetfiddle.net/RXicN9 and check the line numbers. They are different.

a more complete example that shows that only the method with the two try... catch... has its line numbers mangled: https://dotnetfiddle.net/jJyYWB

See Incorrect stacktrace by rethrow for an explanation. Note that this is a special case, that happens only if an exception is thrown twice in the same method.

Community
  • 1
  • 1
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • Can you find a reference for that? I could have sworn it was the case, but would love to figure out how to find this stuff for myself later. Will accept in 12 min. And *whoah* on the `throw` I never knew that. – Chris Pfohl Jun 15 '15 at 14:13
  • 2
    Er... No, that's wrong. That's the whole reason `throw;` is so strongly recommended over `throw ex;`: `throw ex;` overwrites the stack trace, `throw;` does not. See [Is there a difference between “throw” and “throw ex”?](http://stackoverflow.com/questions/730250/is-there-a-difference-between-throw-and-throw-ex) –  Jun 15 '15 at 14:14
  • @xanatos That's because you put everything in a single method, and then things get icky. Put the code that throws the exception in a separate method and you can see a difference between `throw;` and `throw ex;`. (As I now see you figured out already.) –  Jun 15 '15 at 14:20
  • @hvd I've added a little explanation. Still what I wrote was true. Even `throw` will mangle the stack trace. – xanatos Jun 15 '15 at 14:20
  • Looks like this whole mess is what `InnerException` was all about – Chris Pfohl Jun 15 '15 at 14:22
  • @xanatos "Mangle" seems like a good word to me. I think I would not have taken issue with that if you had used that from the start. –  Jun 15 '15 at 14:22
  • I have to point out that the OP didn't actually rethrow anything. He's simply contrasting returning an exception that was thrown, and an exception that was never thrown. There is no rethrowing, neither with `throw ex;` nor `throw;`. – Luaan Jun 15 '15 at 14:27
2

Yes, the two are different. The throw will modify the stack trace information in the Exception object - so your second example will still produce an exception, but without the stack trace information.

Exception-derived classes are classes as any other - all the "magic" happens with the throw keyword.

This is also the reason why it's a bad idea to rethrow the exception by doing throw ex; - you either want to use throw; (although careful about the issue of rethrowing in the same method that Xanatos pointed out), or you want to wrap the inner exception (ie. throw new MyException(ex)). In both cases, there's still some minor changes that can complicate debugging, but if you're well prepared, it helps a lot.

This behaviour is actually quite useful. For one, it means that you can have helper methods that construct exceptions for you to throw (this is used all over the place in .NET code itself). Two, it allows the runtime to actually throw exceptions like StackOverflowException and OutOfMemoryException - both have their instances created when the application starts, and when the issue occurs, they only throw - a new would fail, of course.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • do you have any documentation about the fact that SOE and OOME are pre-allocated? I haven't ever heard of it... – xanatos Jun 15 '15 at 14:29
  • @xanatos Never used windbg? They're always there :) – Luaan Jun 15 '15 at 14:32
  • Some references... http://blogs.msdn.com/b/tess/archive/2009/08/10/why-do-i-see-executionengineexception-stackoverflowexception-and-outofmemoryexception-on-the-heap-when-debugging-net-applications.aspx and http://stackoverflow.com/questions/25271374/outofmemoryexception-is-this-a-false-alarm ... No additional info over what you wrote. – xanatos Jun 15 '15 at 14:34
  • @xanatos As far as I can tell, it's not in the CLR specification either. The three exceptions are treated as special - they can be thrown at any time by any instruction, and are unescapable kill conditions. But the spec doesn't say how they're instantiated (it's not important for CLR behaviour, it really is just almost useless trivia). It's probably just the way the CLR team decided to implement the CLR on Windows - there's other ways around the problem, but this is by far the simplest. Tess' articles were exactly what led me to discovering this originally as well, when I started with SOS. – Luaan Jun 15 '15 at 14:42