How can I rethrow an Inner Exception while maintaining the stack trace generated so far?

后端 未结 8 1929
春和景丽
春和景丽 2021-01-31 05:03

Duplicate of: In C#, how can I rethrow InnerException without losing stack trace?

I have some operations that I invoke asynchronously on a background thread. Sometimes,

相关标签:
8条回答
  • 2021-01-31 05:45

    It is possible to preserve the stack trace before rethrowing without reflection:

    static void PreserveStackTrace (Exception e)
    {
        var ctx = new StreamingContext  (StreamingContextStates.CrossAppDomain) ;
        var mgr = new ObjectManager     (null, ctx) ;
        var si  = new SerializationInfo (e.GetType (), new FormatterConverter ()) ;
    
        e.GetObjectData    (si, ctx)  ;
        mgr.RegisterObject (e, 1, si) ; // prepare for SetObjectData
        mgr.DoFixups       ()         ; // ObjectManager calls SetObjectData
    
        // voila, e is unmodified save for _remoteStackTraceString
    }
    

    This wastes a lot of cycles compared to InternalPreserveStackTrace, but has the advantage of relying only on public functionality. Here are a couple of common usage patterns for stack-trace preserving functions:

    // usage (A): cross-thread invoke, messaging, custom task schedulers etc.
    catch (Exception e)
    {
        PreserveStackTrace (e) ;
    
        // store exception to be re-thrown later,
        // possibly in a different thread
        operationResult.Exception = e ;
    }
    
    // usage (B): after calling MethodInfo.Invoke() and the like
    catch (TargetInvocationException tiex)
    {
        PreserveStackTrace (tiex.InnerException) ;
    
        // unwrap TargetInvocationException, so that typed catch clauses 
        // in library/3rd-party code can work correctly;
        // new stack trace is appended to existing one
        throw tiex.InnerException ;
    }
    
    0 讨论(0)
  • You can't do that. throw always resets the stack trace, unless used without parameter. I'm afraid your callers will have to use the InnerException...

    0 讨论(0)
  • 2021-01-31 05:52

    Using the "throw" keyword with an exception will always reset the stack trace.

    The best thing to do is to catch the actual exception you want, and use "throw;" instead of "throw ex;". Or to throw your own exception, with the InnerException that you want to pass along.

    I don't believe what you want to do is possible.

    0 讨论(0)
  • 2021-01-31 05:53

    As others have said, use the "throw" keyword without adding to it to keep the exception chain intact. If you need that original exception (assuming that is what you mean) then you could call Exception.GetBaseException() at the end of your chain to get the Exception that started it all.

    0 讨论(0)
  • 2021-01-31 05:55

    No, that isn't possible. Your only real opportunity is to follow the recommended pattern and throw your own exception with the appropriate InnerException.

    Edit

    If your concern is the presence of the TargetInvocationException and you want to disregard it (not that I recommend this, as it could very well have something to do with the fact that it's being run on another thread) then nothing is stopping you from throwing your own exception here and attaching the InnerException from the TargetInvocationException as your own InnerException. It's a little smelly, but it might accomplish what you want.

    0 讨论(0)
  • 2021-01-31 06:00

    Although you may feel that the TargetInvocationException is "useless", it's the reality. Don't try to pretend that .NET didn't take the original exception and wrap it with a TargetInvocationException and throw it. That really happened. Some day, you might even want some piece of information that comes from that wrapping - like maybe the location of the code that threw the TargetInvocationException.

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