In C#, how can I rethrow InnerException without losing stack trace?
I am calling, through reflection, a method which may cause an exception. How can I pass the exception to my caller without the wrapper reflection puts around it? I am rethrowing the InnerException, but this destroys the stack trace. Example code:
public void test1()
{
// Throw an exception for testing purposes
throw new ArgumentException("test1");
}
void test2()
{
try
{
MethodInfo mi = typeof(Program).GetMethod("test1");
mi.Invoke(this, null);
}
catch (TargetInvocationException tiex)
{
// Throw the new exception
throw tiex.InnerException;
}
}
In .NET 4.5 there is now the ExceptionDispatchInfo
class.
This lets you capture an exception and re-throw it without changing the stack-trace:
try
{
task.Wait();
}
catch(AggregateException ex)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
}
This works on any exception, not just AggregateException
.
It was introduced due to the await
C# language feature, which unwraps the inner exceptions from AggregateException
instances in order to make the asynchronous language features more like the synchronous language features.
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 calling InternalPreserveStackTrace
via cached delegate, 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 ;
}
I think your best bet would be to just put this in your catch block:
throw;
And then extract the innerexception later.
链接地址: http://www.djcxy.com/p/82436.html