-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
ExceptionDispatchInfo.cs
105 lines (91 loc) · 5.21 KB
/
ExceptionDispatchInfo.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
namespace System.Runtime.ExceptionServices
{
// This class defines support for separating the exception dispatch details
// (like stack trace, watson buckets, etc) from the actual managed exception
// object. This allows us to track error (via the exception object) independent
// of the path the error takes.
//
// This is particularly useful for frameworks that wish to propagate
// exceptions (i.e. errors to be precise) across threads.
public sealed class ExceptionDispatchInfo
{
private readonly Exception _exception;
private readonly Exception.DispatchState _dispatchState;
private ExceptionDispatchInfo(Exception exception)
{
_exception = exception;
_dispatchState = exception.CaptureDispatchState();
}
// This static method is used to create an instance of ExceptionDispatchInfo for
// the specified exception object and save all the required details that maybe
// needed to be propagated when the exception is "rethrown" on a different thread.
public static ExceptionDispatchInfo Capture(Exception source)
{
ArgumentNullException.ThrowIfNull(source);
return new ExceptionDispatchInfo(source);
}
// Return the exception object represented by this ExceptionDispatchInfo instance
public Exception SourceException => _exception;
// When a framework needs to "Rethrow" an exception on a thread different (but not necessarily so) from
// where it was thrown, it should invoke this method against the ExceptionDispatchInfo
// created for the exception in question.
//
// This method will restore the original stack trace and bucketing details before throwing
// the exception so that it is easy, from debugging standpoint, to understand what really went wrong on
// the original thread.
[DoesNotReturn]
[StackTraceHidden]
public void Throw()
{
// Restore the exception dispatch details before throwing the exception.
_exception.RestoreDispatchState(_dispatchState);
throw _exception;
}
// Throws the source exception, maintaining the original bucketing details and augmenting
// rather than replacing the original stack trace.
[DoesNotReturn]
[StackTraceHidden]
public static void Throw(Exception source) => Capture(source).Throw();
/// <summary>Stores the current stack trace into the specified <see cref="Exception"/> instance.</summary>
/// <param name="source">The unthrown <see cref="Exception"/> instance.</param>
/// <exception cref="ArgumentNullException">The <paramref name="source"/> argument was null.</exception>
/// <exception cref="InvalidOperationException">The <paramref name="source"/> argument was previously thrown or previously had a stack trace stored into it.</exception>
/// <returns>The <paramref name="source"/> exception instance.</returns>
[StackTraceHidden]
public static Exception SetCurrentStackTrace(Exception source)
{
ArgumentNullException.ThrowIfNull(source);
source.SetCurrentStackTrace();
return source;
}
/// <summary>
/// Stores the provided stack trace into the specified <see cref="Exception"/> instance.
/// </summary>
/// <param name="source">The unthrown <see cref="Exception"/> instance.</param>
/// <param name="stackTrace">The stack trace string to persist within <paramref name="source"/>. This is normally acquired
/// from the <see cref="Exception.StackTrace"/> property from the remote exception instance.</param>
/// <exception cref="ArgumentNullException">The <paramref name="source"/> or <paramref name="stackTrace"/> argument was null.</exception>
/// <exception cref="InvalidOperationException">The <paramref name="source"/> argument was previously thrown or previously had a stack trace stored into it.</exception>
/// <returns>The <paramref name="source"/> exception instance.</returns>
/// <remarks>
/// This method populates the <see cref="Exception.StackTrace"/> property from an arbitrary string value.
/// The typical use case is the transmission of <see cref="Exception"/> objects across processes with high fidelity,
/// allowing preservation of the exception object's stack trace information. .NET does not attempt to parse the
/// provided string value.
///
/// The caller is responsible for canonicalizing line endings if required. <see cref="string.ReplaceLineEndings"/>
/// can be used to canonicalize line endings.
/// </remarks>
public static Exception SetRemoteStackTrace(Exception source, string stackTrace)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(stackTrace);
source.SetRemoteStackTrace(stackTrace);
return source;
}
}
}