7

As all of you probably know, catching and re-throwing a exception in c# this way is evil, because it destroys the stack trace:

try
{
    if(dummy)
        throw new DummyException();
}
catch (DummyException ex)
{
    throw ex;
}

The right way to re-throw an exception without loosing the stack trace is this:

try
{
    if(dummy)
        throw new DummyException();
}
catch (DummyException ex)
{
    throw;
}

The only problem with this is that I get a lot of compilation warnings: "The variable 'ex' is declared but never used". If you have a lot of these, a useful warning may be hidden in the garbage. So, that's what I did:

try
{
    if(dummy)
        throw new DummyException();
}
catch (DummyException)
{
    throw;
}
catch(AnotherException ex)
{
    //handle it
}

This seems to work, but I'd like to know if there is any downside of re-throwing an exception that is not set to an variable. How does .net threats this?

Thanks in advance

Edit: I've changed my code a little bit to make clearer what I wanted to do, as some had misunderstood

Ortiga
  • 8,455
  • 5
  • 42
  • 71
  • Erm, why in the world do you throw an exception, catch it, and rethrow it **all from the same method**? – Cody Gray - on strike May 02 '11 at 15:13
  • 1
    @Cody Gray- I'm just guessing, here, but (giving the benefit of the doubt) I'm guessing he's just providing example code to show that he understands the difference between `throw` and `throw ex`. Not that he's actually generating an exception within a method- catching that exception- and then rethrowing it. I hope, anyway. – AllenG May 02 '11 at 15:28
  • 2
    @Cody Gray, @AllenG is right, it's just an simple example to show what I'm trying to achieve, not a real code – Ortiga May 02 '11 at 15:50
  • Okay, good. That's what I was hoping, and why I posted that as a comment rather than an answer. You'd be surprised at the kind of craziness I see people do on here with throwing/catching exceptions. – Cody Gray - on strike May 02 '11 at 15:52

6 Answers6

9

I'd like to know if there is any downside of re-throwing an exception that is not set to an variable.

No, there's no downside at all. A variable is only needed if you want to reference the exception in your code, but since you don't need to do that with a throw statement, you don't need a variable at all.

And you have exactly the right idea in attempting to eliminate "noisy" compiler warnings. They have a tendency to bury important errors that you do want to fix, and getting a clean build is always important. The best solution is simply to rewrite the code to use a parameterless catch clause.

However, be aware that in 82% of cases that I see*, it's a mistake to write code that uses throw at all. You generally shouldn't catch exceptions that you don't know how to handle and your only intended "handling" strategy is to rethrow them. There are cases where even using throw can reset the call stack, causing you to lose important debugging information. There are also better alternatives for logging exceptions to catching/rethrowing. You can find more information in the answers to these questions:

There's absolutely nothing wrong with letting exceptions bubble up and handling them all in a central place. The rule to keep in mind is that you shouldn't use exceptions for flow control. But there's nothing wrong with throwing an exception in low level code, and showing the user an error message higher up the stack in UI code. Read Microsoft's Best Practices for Handling Exceptions for some general tips.


* Slightly more than the percent of statistics that are made up on the spot.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • thanks for your answer, that's exactly what I was looking for. I've already did a lot of mistakes in exception handling, but I think I'm getting a little better with it now. I usually handle them inside the method or one layer up, avoiding it going too many layers up. I usually throw an unchecked exception that bubble up and give a generic error message to the user. Is it a bad practice? – Ortiga May 02 '11 at 16:14
  • @andre: There's absolutely nothing wrong with letting exceptions bubble up and handling them all in a central place. The rule to keep in mind is that you shouldn't use exceptions for flow control. But there's nothing wrong with throwing an exception in low level code, and showing the user an error message higher up the stack in UI code. You'd probably have to post real sample code for me to be any more specific. But you should read Microsoft's [Best Practices for Handling Exceptions](http://msdn.microsoft.com/en-us/library/seyhszts.aspx) for some general tips. – Cody Gray - on strike May 02 '11 at 16:25
8

There is no downside to that. You are simply telling the compiler "I plan to catch this exception but I have no need for a reference to the actual exception", it doesn't affect how things are thrown or how exceptions work. Your latter example is the ideal way to do what you want, however if you are merely going to immediately throw; with nothing else whatsoever in the block, then why catch at all?

Matt Greer
  • 60,826
  • 17
  • 123
  • 123
5

If you're not doing anything with DummyException in the catch block (which you can't, since you haven't given it an identifier), why not get rid of the try/catch block entirely? E.g., just do this:

throw new DummyException();

Although at that point, I'd probably evaluate what you're trying to accomplish here and rethink your application architecture so as not to not rely on exception propagation in this manner.

Donut
  • 110,061
  • 20
  • 134
  • 146
  • 1
    The reason you might catch `DummyException` specifically and just re-throw it is that you might be handling it at a higher (closer to the UI) level. And `try/catch` allows you to a) include a `finally` if you need one, and b) to catch multiple exceptions. – AllenG May 02 '11 at 15:13
  • @AllenG it's ok to have a `try/finally` which has no `catch` blocks. I don't know for sure but I wouldn't be surprised if the compiler optimized out his catch altogether. – Matt Greer May 02 '11 at 15:14
  • @MattGree: true: but you still need the `try`. I was referring to the suggestion to "get rid of the `try/catch` block entirely" which you wouldn't want to do- since you'd at least need the `try`. – AllenG May 02 '11 at 15:17
  • @AllenG Good points worth considering; my answer was based off the OP's example (no other `catch` blocks and no `finally`). – Donut May 02 '11 at 15:25
  • @Donut, i gave this example because it shows my problem - not using the variable if I'm going to re-throw, what gives me a compiler warning. In a real code, I would have multiple catches and/or a finally block – Ortiga May 02 '11 at 15:58
  • @Andre Fair enough, although I'd argue that passing the unhandled exception up the stack has some disadvantages (i.e., creating multiple exit points from the function). – Donut May 02 '11 at 16:00
1

Why catch if your simply going to re-throw? Anyway, you may want to take a look at this previous discussion. Though not identical much of what is discussed is relevant:

Throw VS rethrow : same result?

Community
  • 1
  • 1
Roja Buck
  • 2,354
  • 16
  • 26
  • thanks for the link. Answering your question, the code is just an example, I may re-throw one kind of exception but not others (if having multiple catch blocks) – Ortiga May 02 '11 at 15:53
1

Actually throwing an exception using "throw;" is a .Net best practice, because it preserves exception stack trace.

Throwing exceptions using "throw ex;" is considered a worst practice, because it looses the original stack trace and should be avoided.

Pop Catalin
  • 61,751
  • 23
  • 87
  • 115
1

Why catch and rethrow like this? Why do people always have to assume they know every case? Answer: Database transactions.

If you have a better way to do this please speak up Dr. Proton, no offense taken. Keep in mind that there are a lot of different database systems in use but most of them support transaction control (begin/commit/rollback) and have C# interfaces.

pseudocode (a simplified case):

try
{
   db.beginTrans();

   db.doStuff();

   db.doOtherStuff();

   db.commitTrans();
}
catch
{
  db.rollbackTrans();
  throw;
}

Now, it is quite annoying to lose the detail of whether doStuff() or doOtherStuff() failed and I don't see any good reason why C# would toss the line number information in this case. But it seems to. Hence the googling and my subsequent arrival. If I am missing something please do tell.

AnotherOne
  • 11
  • 1
  • 1
    Here is a post I found which offers some insight and a possible solution: http://weblogs.asp.net/fmarguerie/archive/2008/01/02/rethrowing-exceptions-and-preserving-the-full-call-stack-trace.aspx – AnotherOne Jul 13 '11 at 20:10