1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Diagnostics; 7 8 namespace System.Runtime.ExceptionServices 9 { 10 // This class defines support for seperating the exception dispatch details 11 // (like stack trace, watson buckets, etc) from the actual managed exception 12 // object. This allows us to track error (via the exception object) independent 13 // of the path the error takes. 14 // 15 // This is particularly useful for frameworks like PFX, APM, etc that wish to 16 // propagate exceptions (i.e. errors to be precise) across threads. 17 public sealed class ExceptionDispatchInfo 18 { 19 // Private members that will hold the relevant details. 20 private Exception _exception; 21 private Exception.EdiCaptureState _ediCaptureState; 22 ExceptionDispatchInfo(Exception exception)23 private ExceptionDispatchInfo(Exception exception) 24 { 25 _exception = exception; 26 _ediCaptureState = exception.CaptureEdiState(); 27 } 28 29 // This static method is used to create an instance of ExceptionDispatchInfo for 30 // the specified exception object and save all the required details that maybe 31 // needed to be propagated when the exception is "rethrown" on a different thread. Capture(Exception source)32 public static ExceptionDispatchInfo Capture(Exception source) 33 { 34 if (source == null) 35 { 36 throw new ArgumentNullException(nameof(source), SR.ArgumentNull_Obj); 37 } 38 39 return new ExceptionDispatchInfo(source); 40 } 41 42 // Return the exception object represented by this ExceptionDispatchInfo instance 43 public Exception SourceException 44 { 45 get 46 { 47 return _exception; 48 } 49 } 50 51 // When a framework needs to "Rethrow" an exception on a thread different (but not necessarily so) from 52 // where it was thrown, it should invoke this method against the ExceptionDispatchInfo (EDI) 53 // created for the exception in question. 54 // 55 // This method will restore the original stack trace and bucketing details before throwing 56 // the exception so that it is easy, from debugging standpoint, to understand what really went wrong on 57 // the original thread. 58 [StackTraceHidden] Throw()59 public void Throw() 60 { 61 // Restore the exception dispatch details before throwing the exception. 62 _exception.RestoreEdiState(_ediCaptureState); 63 throw _exception; 64 } 65 66 // Throws the source exception, maintaining the original bucketing details and augmenting 67 // rather than replacing the original stack trace. 68 public static void Throw(Exception source) => Capture(source).Throw(); 69 } 70 } 71