what can lead throw to reset a callstack (I'm using “throw”, not “throw ex”)

后端 未结 3 1167
别跟我提以往
别跟我提以往 2020-11-30 00:35

I\'ve always thought the difference between \"throw\" and \"throw ex\" was that throw alone wasn\'t resetting the stacktrace of the exception.

Unfortunately, that\'s

相关标签:
3条回答
  • 2020-11-30 01:23

    The normal rethrow preserves everything on the stack trace except that if the present method is in the stack trace, the line number will get overwritten. This is annoying behavior. In C# if one needs to do something in the exceptional case but doesn't care what the exception is, one can use the pattern:

      Boolean ok = False;
      try
      {
        do_something();
        ok = True;
      }
      finally
      {
        if (!ok) // An exception occurred!
          handle_exception();
      }
    

    There are a number where that pattern is very helpful; the most common would be a function which is supposed to return a new IDisposable. If the function isn't going to return, the disposable object must get cleaned up. Note that any "return" statements within the above "try" block must set ok to true.

    In vb.net, it's possible to use a pattern which is functionally a little nicer, though one spot in the code is a little icky, with the pattern:

      Dim PendingException As Exception = Nothing;
      Try
        Do_Something
        PendingException = Nothing ' See note
      Catch Ex As Exception When CopyFirstParameterToSecondAndReturnFalse(Ex, PendingException )
        Throw ' Will never execute, since above will return false
      Finally
        If PendingException IsNot Nothing Then
          .. Handle exception
        EndIf
      End Try
    

    The long-named function should be implemented in the obvious fashion. This pattern has the advantage of making the exception available to the code. While that isn't often needed in handle-but-don't-catch situations, there's one situation where it can be invaluable: if a cleanup routine throws an exception. Normally, if a cleanup routine throws an exception, any pending exception will be lost. With the above pattern, however, it's possible to wrap the pending exception within the cleanup exception.

    One interesting note with the above code: it's possible for an exception to reach the "Catch When" and yet for the Try statement to complete normally. It's really not clear what should happen in that circumstance, but one thing that is clear is that the Finally statement should not act as though an exception is pending. Clearing PendingException will make it so that if an exception vanishes, the code will behave as though it never happened. An alternative would be to wrap and rethrow an exception which is known to have occurred, since that situation almost certainly indicates something wrong with the inner exception-handling code.

    0 讨论(0)
  • 2020-11-30 01:30

    You should read this article:

    • Rethrowing exceptions and preserving the full call stack trace

    In short, throw usually preserves the stack trace of the original thrown exception, but only if the exception didn't occur in the current stack frame (i.e. method).

    There is a method PreserveStackTrace (shown in that blog article) that you use that preserves the original stack trace like this:

    try
    {
    
    }
    catch (Exception ex)
    {
        PreserveStackTrace(ex);
        throw;
    }
    

    But my usual solution is to either simply to not catch and re throw exceptions like this (unless absolutely necessary), or just to always throw new exceptions using the InnerException property to propagate the original exception:

    try
    {
    
    }
    catch (Exception ex)
    {
         throw new Exception("Error doing foo", ex);
    }
    
    0 讨论(0)
  • 2020-11-30 01:30

    The problem is that Windows is resetting the stack's starting point. The CLR is behaving as expected—this is just a limitation of the host operating system's exception handling support. The problem is that there can only be one stack frame per method call.

    You could extract your exception handling routines into a separate "helper" method, which would work around the limitations imposed by Windows's SEH, but I don't think that's necessarily a good idea.

    The proper way to rethrow an exception without losing the stack information is to throw a new exception and include the original, caught exception as the inner exception.

    It's difficult to imagine very many cases where you'd really need to do this. If you're not handling the exception, and simply catching it to rethrow it, you probably shouldn't be catching it in the first place.

    0 讨论(0)
提交回复
热议问题