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, things go bad. When this happens, I tend to get a TargetInvocationException, which, while appropriate, is quite useless. What I really need is the TargetInvocationException's InnerException, like this:
try
{
ReturnValue = myFunctionCall.Invoke(Target, Parameters);
}
catch (TargetInvocationException err)
{
throw err.InnerException;
}
That way, my callers are served up with the REAL exception that occured. The problem is, that the throw statement seems to reset the stack trace. I'd like to basically rethrow the inner exception, but keep the stack trace it originally had. How do I do that?
CLARIFICATION: The reason I want only the inner exception is that this class tries to 'abstract away' the whole fact that these functions (delegates supplied by caller) are run on other threads and whatnot. If there is an exception, then odds are it has nothing to do with being run on a background thread, and the caller would really like the stack trace that goes into their delegate and finds the real issue, not my call to invoke.
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 ;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With