30

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.

Community
  • 1
  • 1
dance2die
  • 35,807
  • 39
  • 131
  • 194
  • What do you mean "extract a new error handling method"? – Marc Gravell Apr 08 '09 at 14:33
  • I am actually more interested in how to emulate "throw;" within an extracted error handling method. – dance2die Apr 08 '09 at 14:48
  • You cannot do a "throw;" inside of the extracted method itself, since the method may also be called without coming from a catch block (imagine for instance calling it with "new Exception()" as argument). The only way to achieve this is probably the one suggested in my answer with the return code. – Lucero Apr 08 '09 at 15:08

5 Answers5

56

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.
    }
}
Zarat
  • 2,584
  • 22
  • 40
  • 6
    @KonstantinSpirin: Thought the available methods and MSDN docs were pretty obvious, but added some sample code anyways to given an overview without having to click over to MSDN. – Zarat Jan 08 '13 at 04:41
  • 1
    This is exactly what I want, but sadly I'm not on 4.5 for my current project. But +1 for making me aware of this nice new feature. – AnorZaken Oct 13 '15 at 02:37
  • Can I put this in new exception class? – Murat Can OĞUZHAN Mar 13 '23 at 14:27
  • @MuratCanOĞUZHAN these are static helper methods which are already available to everyone, so there is little use of putting it on the exception itself; you could make them extensions methods if you wanted though, for better discoverability – Zarat Mar 15 '23 at 10:21
51

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.

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • 3
    The downside of this approach in practice is that many error logs only contain details of the topmost exception. [This approach](http://stackoverflow.com/a/12619055/24874) avoids this. – Drew Noakes Jan 07 '17 at 22:32
34

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;
  }
}
Lucero
  • 59,176
  • 9
  • 122
  • 152
  • +marked as answer: seems like the easiest to trace error back to the source and easy to read. My "HandleException" method is named as "TryHandleRecoverableException", by the way. – dance2die Apr 08 '09 at 15:25
  • This will still screw up the stack trace if the error was thrown at the same stack level as the catch block (for instance, a NullReferenceException will get screwed). See https://stackoverflow.com/a/11284872/1739000 – NH. Jun 28 '19 at 16:37
5

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?

Brian Genisio
  • 47,787
  • 16
  • 124
  • 167
3

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.

J.Merrill
  • 1,233
  • 14
  • 27
Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
  • "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?" -> Yes. – dance2die Apr 08 '09 at 14:56
  • "finally" code is always executed, no matter whether an exception occurred and how you handle the exception. I don't see the relation to the question... – Lucero Apr 08 '09 at 15:05
  • +1 for the link.. a useful thing that VB has and C# doesn't... strange. Maybe its because the C# designers want you to catch specific exceptions and design exception hierarchies correctly so that you dont have to catch and rethrow few specific derivations – Gishu Apr 08 '09 at 15:29
  • +1 Earwicker, your 2cents was really great. I would love to use "Exceptions" class somewhere in the code as well. – dance2die Apr 08 '09 at 15:32
  • @Lucero - not necessarily. Try handling AppDomain.UnhandledException and you will find that it fires _before_ finally blocks run, giving you the option to call Environment.FailFast before they do. But any intervening catch/rethrow will interfere with this capability. – Daniel Earwicker Apr 08 '09 at 15:48
  • The relation to the question is straightforward - Sung Meister IS doing the thing I asked about, and so my advice is "Don't do it that way". – Daniel Earwicker Apr 08 '09 at 15:48
  • @Gishu - yes I'm sure that's the reason. But unfortunately that requires predictive powers that class library designers don't have access to, even the BCL team itself! The whole history of SystemException vs. ApplicationException is very illuminating here. – Daniel Earwicker Apr 08 '09 at 15:56
  • You had me worried for a minute, but I don't think this is actually a problem. The only possible difference in the "finally" behaviour is between exceptions which are totally uncaught (i.e. which will terminate the runtime) and ones which are caught higher up the callstack. In most applications (webapps, desktop apps) you never want to allow a hard crash, so this distinction never arises, since there is always some kind of handler higher up somewhere. – Rich Jul 18 '12 at 17:13
  • @Rich - it depends. An unexpected exception implies an unexpected program state. If you are happy to take a chance and have your application limp along in an unknown state, then you can catch all exceptions. But this isn't always acceptable; you may be worried that the "unknown state" could lead to corruption of valuable persistent data (e.g. deleting the wrong file, launching the wrong missiles, killing the wrong patient). So sometimes it is necessary to let software crash, in order to be more robust! It's a way of containing a potential disaster of entirely unknown scope. – Daniel Earwicker Jul 18 '12 at 17:34
  • @Daniel, I think you are being overly pessimistic. In a managed language like C#, even the most unexpected exception is guaranteed to not corrupt anything upstack. There are plently of cases where catching all exceptions is totally justified. For example, say a webserver has an unexpected exception while rendering a page: a null-ref; even an out-of-memory exception (say the user requested too many results). You don't want to kill the entire server process in these cases: much better to surround each request with a catch all exceptions block. Subsequent requests will execute just fine. – Rich Jul 20 '12 at 08:40
  • "In a managed language like C#, even the most unexpected exception is guaranteed to not corrupt anything upstack." Your mistake here is to equate "unknown state" purely with low-level memory corruption. Trivial example: a field called `fileToDeleteLater` which should be `null` (so nothing will get deleted). Unfortunately due to a bug it contains the path to a file that shouldn't be deleted, so that file gets deleted. Why does `fileToDeleteLater` contain that string? It was going to be set to `null`, but an unexpected exception was thrown before that could happen. It was caught and the ... – Daniel Earwicker Jul 20 '12 at 11:52
  • ... program continued to limp along in an unknown state, and at some later time it happily deleted the file in `fileToDeleteLater`. Managed languages greatly reduce the degrees of freedom within a program's state, but they don't magically reduce them down so that only desirable states are accessible. – Daniel Earwicker Jul 20 '12 at 11:54
  • No, I don't mean just memory corruption, I mean everything about how the program operates. If you use scoping correctly, for example "using" blocks instead of `fileToDeleteLater` global variables (a very bad idea) then everything can be made predictable in the face of unexpected exceptions. There isn't really any option in web programming other than catching all exceptions, if you don't want your whole web server to die every time someone makes a coding error on one page out of hundreds. – Rich Jul 20 '12 at 13:51
  • "If you use scoping correctly..." - that is, if you don't put any state corrupting bugs in your code. Assuming that is universally true, obviously none of this is a problem! By definition, a bug is a situation where you *didn't* do something correctly. – Daniel Earwicker Jul 20 '12 at 13:59
  • The "detailed explanation" blog post no longer exists, except in the Internet Archive. Add https://web.archive.org/web/20091218171254/ to the front of the URL to avoid a broken link. (I tried to just edit the URL without bringing this to anyone's attention, but the edit was inexplicably rejected -- why should anyone else have to do anything about this? And there's no way to talk to the rejecting person that I could find; sigh.) – J.Merrill Dec 13 '14 at 22:50