I understand the value of ExceptionDispatchInfo.Capture(e).Throw()
(preserves the original stack trace), but what's the advantage of using Capture
early and passing the ExceptionDispatchInfo
around vs. just passing the caught Exception
around?
As a concrete example, comparing
static Exception CaptureException(Action action) { try { action(); return null; } catch (Exception e) { return e; } } public void Test1() { ExceptionDispatchInfo.Capture(CaptureException( () => throw new IOException("Test"))) .Throw(); }
with
static ExceptionDispatchInfo CaptureDispatchInfo(Action action) { try { action(); return null; } catch (Exception e) { return ExceptionDispatchInfo.Capture(e); } } public void Test2() { CaptureDispatchInfo(() => throw new IOException("Test")).Throw(); }
, both give essentially the same stack traces (It's similar for an async
variation of this.). So, I don't really get why the ExceptionDispatchInfo
class exists at all, rather than just a combined ExceptionDispatchInfo.Capture(e).Throw()
method.
Upon determining that a catch block cannot sufficiently handle an exception, the exception should be rethrown using an empty throw statement. Regardless of whether you're rethrowing the same exception or wrapping an exception, the general guideline is to avoid exception reporting or logging lower in the call stack.
If a catch block cannot handle the particular exception it has caught, you can rethrow the exception. The rethrow expression ( throw without assignment_expression) causes the originally thrown object to be rethrown.
The ExceptionDispatchInfo object stores the stack trace information and Watson information that the exception contains at the point where it is captured. The exception can be thrown at another time and possibly on another thread by calling the ExceptionDispatchInfo. Throw method.
To rethrow an exception, you can use the <throw> keyword.
You're assuming that exceptions are immutable. This is not the case - an exception's StackTrace changes when it's re-thrown.
The purpose of ExceptionDispatchInfo.Capture
is to capture a potentially mutating exception's StackTrace at a point in time:
void Foo() => throw new InvalidOperationException ("foo"); Exception original = null; ExceptionDispatchInfo dispatchInfo = null; try { try { Foo(); } catch (Exception ex) { original = ex; dispatchInfo = ExceptionDispatchInfo.Capture (ex); throw ex; } } catch (Exception ex2) { // ex2 is the same object as ex. But with a mutated StackTrace. Console.WriteLine (ex2 == original); // True } // So now "original" has lost the StackTrace containing "Foo": Console.WriteLine (original.StackTrace.Contains ("Foo")); // False // But dispatchInfo still has it: try { dispatchInfo.Throw (); } catch (Exception ex) { Console.WriteLine (ex.StackTrace.Contains ("Foo")); // True }
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