How to throw exception without resetting stack trace?

28,693

Solution 1

Not sure if you mean that, but my suggestion in your other question was addressing this.

If your handler returns a boolean whether the exception was handled or not, you can use this in your catch clause:

catch (Exception ex) {
  if (!HandleException(ex)) {
    throw;
  }
}

Solution 2

With .NET Framework 4.5 there is now an ExceptionDispatchInfo which supports this exact scenario. It allows capturing a complete exception and rethrowing it from somewhere else without overwriting the contained stack trace.

code sample due to request in comment

using System.Runtime.ExceptionServices;

class Test
{
    private ExceptionDispatchInfo _exInfo;

    public void DeleteNoThrow(string path)
    {
        try { File.Delete(path); }
        catch(IOException ex)
        {
            // Capture exception (including stack trace) for later rethrow.
            _exInfo = ExceptionDispatchInfo.Capture(ex);
        }
    }

    public Exception GetFailure()
    {
        // You can access the captured exception without rethrowing.
        return _exInfo != null ? _exInfo.SourceException : null;
    }

    public void ThrowIfFailed()
    {
        // This will rethrow the exception including the stack trace of the
        // original DeleteNoThrow call.
        _exInfo.Throw();

        // Contrast with 'throw GetFailure()' which rethrows the exception but
        // overwrites the stack trace to the current caller of ThrowIfFailed.
    }
}

Solution 3

Yes; That's what the InnerException property is for.

catch(Exception ex)
{
    throw new YourExceptionClass("message", ex);
}

This will allow you to add your own logic, then throw your own exception class. The StackTrace of the YourExceptionClass instance will be from within this code block, but the InnerException will be the exception you caught, with the StackTrace it had before.

Solution 4

You don't want to create a new exception with the original stack trace. That is misleading, since that stack trace did not create the new exception.

You can, however, put the original exception in your new exception as an "InnerException". Would that do what you are looking for?

Solution 5

Are you catching exceptions that you want to then filter more carefully, so you can then change your mind, decide not to handle them and so rethrow them?

If you want to be really careful about this, that's not really a good idea. It's better to never catch the exception in the first place. The reason is that a given try/catch handler should not take the decision to run nested finally blocks for exceptions that it is not expecting to see. For example, if there is a NullReferenceException, it's probably a very bad idea to continue executing any code as it will probably cause another such exception to be thrown. And finally blocks are just code, like any other code. As soon as an exception is caught for the first time, any finally blocks on the stack beneath the try/catch will be executed, by which time it's too late - another exception may be generated, and this means that the original exception is lost.

This implies (in C#) that you have to careful write out a separate catch handler for all the exception types you want to catch. It also implies that you can only filter by exception type. This is sometimes very hard advice to follow.

It should be possible to filter exceptions in other ways, but in C# it is not. However, it is possible in VB.NET, and the BCL itself takes advantage of this by having a small amount of code written in VB.NET so it can filter exceptions in a more convenient way.

Here's a detailed explanation, with a VB.NET code sample, from the CLR team blog.

And here's my two cents.

Share:
28,693
dance2die
Author by

dance2die

I like to read, and build(& break?) stuff. Currently helping folks out on r/reactjs & DEV#react. Reach out to me @dance2die & check out my blog on sung.codes

Updated on December 14, 2020

Comments

  • dance2die
    dance2die over 3 years

    This is a follow-up question to Is there a difference between “throw” and “throw ex”?

    is there a way to extract a new error handling method without resetting the stack trace?

    [EDIT] I will be trying both "inner method" and another answer provided by Earwicker and see which one can work out better to mark an answer.