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