This repository has been archived by the owner on Jun 11, 2021. It is now read-only.
forked from dotnet/dotNext
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Disposable.cs
152 lines (134 loc) · 6.16 KB
/
Disposable.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace DotNext
{
using static Runtime.Intrinsics;
/// <summary>
/// Provides implementation of dispose pattern.
/// </summary>
/// <see cref="IDisposable"/>
/// <seealso href="https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose">Implementing Dispose method</seealso>
public abstract class Disposable : IDisposable
{
private volatile bool disposed;
/// <summary>
/// Indicates that this object is disposed.
/// </summary>
protected bool IsDisposed => disposed;
private string ObjectName => GetType().Name;
/// <summary>
/// Throws exception if this object is disposed.
/// </summary>
/// <exception cref="ObjectDisposedException">Object is disposed.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected void ThrowIfDisposed()
{
if (IsDisposed)
throw new ObjectDisposedException(ObjectName);
}
/// <summary>
/// Gets a task representing <see cref="ObjectDisposedException"/> exception.
/// </summary>
protected Task DisposedTask => Task.FromException(new ObjectDisposedException(ObjectName));
/// <summary>
/// Returns a task representing <see cref="ObjectDisposedException"/> exception.
/// </summary>
/// <typeparam name="T">The type of the task.</typeparam>
/// <returns>The task representing <see cref="ObjectDisposedException"/> exception.</returns>
protected Task<T> GetDisposedTask<T>()
=> Task.FromException<T>(new ObjectDisposedException(ObjectName));
/// <summary>
/// Attempts to complete the task with <see cref="ObjectDisposedException"/> exception.
/// </summary>
/// <param name="source">The task completion source.</param>
/// <typeparam name="T">The type of the task.</typeparam>
/// <returns><see langword="true"/> if operation was successful; otherwise, <see langword="false"/>.</returns>
protected bool TrySetDisposedException<T>(TaskCompletionSource<T> source)
=> source.TrySetException(new ObjectDisposedException(ObjectName));
/// <summary>
/// Releases managed and unmanaged resources associated with this object.
/// </summary>
/// <param name="disposing"><see langword="true"/> if called from <see cref="Dispose()"/>; <see langword="false"/> if called from finalizer <see cref="Finalize()"/>.</param>
protected virtual void Dispose(bool disposing) => disposed = true;
/// <summary>
/// Releases managed resources associated with this object asynchronously.
/// </summary>
/// <remarks>
/// This method makes sense only if derived class implements <see cref="IAsyncDisposable"/> interface.
/// </remarks>
/// <returns>The task representing asynchronous execution of this method.</returns>
protected virtual ValueTask DisposeAsyncCore()
{
Dispose(true);
return new ValueTask();
}
private async ValueTask DisposeAsyncImpl(bool continueOnCapturedContext)
{
await DisposeAsyncCore().ConfigureAwait(continueOnCapturedContext);
Dispose(false);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases managed resources associated with this object asynchronously.
/// </summary>
/// <remarks>
/// If derived class implements <see cref="IAsyncDisposable"/> then <see cref="IAsyncDisposable.DisposeAsync"/>
/// can be trivially implemented through delegation of the call to this method.
/// </remarks>
/// <param name="continueOnCapturedContext"><see langword="true"/> to attempt to marshal the continuation back to the captured context; otherwise, <see langword="false"/>.</param>
/// <returns>The task representing asynchronous execution of this method.</returns>
protected ValueTask DisposeAsync(bool continueOnCapturedContext) => disposed ? new ValueTask() : DisposeAsyncImpl(continueOnCapturedContext);
/// <summary>
/// Releases all resources associated with this object.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Disposes many objects.
/// </summary>
/// <param name="objects">An array of objects to dispose.</param>
public static void Dispose(IEnumerable<IDisposable?> objects)
{
foreach (var obj in objects)
obj?.Dispose();
}
/// <summary>
/// Disposes many objects.
/// </summary>
/// <param name="objects">An array of objects to dispose.</param>
/// <returns>The task representing asynchronous execution of this method.</returns>
public static async ValueTask DisposeAsync(IEnumerable<IAsyncDisposable?> objects)
{
foreach (var obj in objects)
{
if (obj is not null)
await obj.DisposeAsync().ConfigureAwait(false);
}
}
/// <summary>
/// Disposes many objects in safe manner.
/// </summary>
/// <param name="objects">An array of objects to dispose.</param>
public static void Dispose(params IDisposable?[] objects)
{
for (nint i = 0; i < GetLength(objects); i++)
objects[i]?.Dispose();
}
/// <summary>
/// Disposes many objects in safe manner.
/// </summary>
/// <param name="objects">An array of objects to dispose.</param>
/// <returns>The task representing asynchronous execution of this method.</returns>
public static ValueTask DisposeAsync(params IAsyncDisposable?[] objects)
=> DisposeAsync(objects.As<IEnumerable<IAsyncDisposable?>>());
/// <summary>
/// Finalizes this object.
/// </summary>
~Disposable() => Dispose(false);
}
}