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; } }
No of course not. There are cases when comment is still needed because the programming languages are not always best suited to describe what is going on very well.
If a catch block cannot handle the particular exception it has caught, we can rethrow the exception. The rethrow expression causes the originally thrown object to be rethrown.
Re-throwing an Exception The catch block simply throws that exception using only throw keyword (not throw e). This will be handled in catch block in Method1() where it again re-throw the same exception and finally it is being handled in the Main() method.
Unlike throw ex, throw provides all stack information. The main difference between throw and throw ex in C# is that throw provides information about from where the exception was thrown and also about the actual exception while throw ex provides information only about from where the exception was thrown.
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:
using ExceptionDispatchInfo = System.Runtime.ExceptionServices.ExceptionDispatchInfo; 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 ; }
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