views:

188

answers:

2

Consider this method (pardon the sad attempt at Chuck Norris humor :) ):

public class ChuckNorrisException : Exception
{
    public ChuckNorrisException()
    {
    }

    public ChuckNorrisException(string message)
        : base(message)
    {
    }

    public ChuckNorrisException(string message, Exception cause)
        : base(message, cause)
    {
    }

    protected ChuckNorrisException(SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
    }
}

static void ExceptionTest(double x)
{
    try
    {
        double y = 10 / x;
        Console.WriteLine("quotient = " + y);
    }
    catch (Exception e)
    {
        e = e is DivideByZeroException ? new ChuckNorrisException("Only Chuck Norris can divide by 0!", e) :
            e;
        throw e;
    }
}

In resharper, I get a warning on the "throw e" line saying "Exception rethrow possibly intended". But obviously in this case that's not the intention, since e could be wrapped in ChuckNorrisException, and if I just use "throw", that wrapped exception wouldn't get thrown.

I know I can suppress the resharper warning, but then it will be turned off for all scenarios if I'm not mistaken. I just wondered if anybody else had encountered this. The only workaround I've found is to make another exception variable (e2, for example), and throw that. That may be the best I can do here. Seems like resharper could detect this issue though and be smart enough to know that if e is modified, then throw e is ok.

Thanks.

[EDIT] Sorry, I forgot a step. Before the throw, I need to log the exception, so I can't just do:

e = e is DivideByZeroException ? new ChuckNorrisException("Only Chuck Norris can divide by 0!", e) :
            e;
throw e;

I have to do:

e = e is DivideByZeroException ? new ChuckNorrisException("Only Chuck Norris can divide by 0!", e) :
            e;
LogException(e);
throw e;
+8  A: 

Maybe I'm not understanding the question, so please correct me if I've got the wrong end of the stick.

There's two cases going on here:

  1. The first is that you catch the original exception. You then wrap it in a new exception instance as the inner exception, then throw the new one. No information is lost in this case (the inner exception preserves all information), so no warning is given.

  2. The second is that you catch and re-throw the original exception. If you re-throw, you should never use "throw e", as it will tamper with the stack trace. This is why ReSharper is printing a warning. To re-throw the caught exception, you should use the "throw" keyword on its own.

The answer to this question explains it better than I can. Due to the subtle side effects and the sheer number of people who get this detail wrong, I personally view the re-throw syntax as flawed.

Anyway that's a description of why you're getting a warning. Here's what I'd do about it instead:

catch(DivideByZeroException e)
{
    // we don't catch any other exceptions because we weren't
    // logging them or doing anything with the exception before re-throwing
    throw new ChuckNorrisException("Useful information", e);
}

*Edit -- if you need to log exceptions, you can just do something like this instead. Note: This is my preferred solution as I think it reads better and is less likely to contain an error than querying for exception types yourself:

// catch most specific exception type first
catch(DivideByZeroException e)
{
    Log(e); 
    throw new ChuckNorrisException("Useful information", e);
} 
catch(Exception e) // log & re-throw all other exceptions
{
    Log(e);
    throw; // notice this is *not* "throw e"; this preserves the stack trace
}

Another alternative would be:

catch(Exception e)
{
    Log(e);
    if(e is DivideByZeroException)
    {
        // wrap + throw the exception with our new exception type
        throw new ChuckNorrisException("useful info", e);
    }

    // re-throw the original, preserving the stack trace
    throw;
}
Mark Simpson
Thanks for the answer, but I left out a step in my original question (I do need to log the exception). Sorry for that.
dcp
Great answer! I did not know that about "throw e" messing with the stack trace. By the way, in case anyone else is interested here is a good link on this topic in case you want to learn more: http://www.tkachenko.com/blog/archives/000352.htmlOne thing I didn't know either is that this behavior is different in C# vs. JAVA.Thanks again Mark!
dcp
Glad to help :)
Mark Simpson
+1  A: 

This will have the same effect as the code you have posted and should not cause the warning.

catch (DivideByZeroException de)
    {
        throw new ChuckNorrisException("Only Chuck Norris can divide by 0!", de);
    }
}
AdamRalph
You are right, however, I left out a step in my original question (my fault). Sorry for that.
dcp