|
|
@@ -11,51 +11,75 @@ namespace System.Reactive.Disposables
|
|
|
{
|
|
|
public sealed class CompositeAsyncDisposable : IAsyncDisposable
|
|
|
{
|
|
|
- private readonly AsyncLock gate = new AsyncLock();
|
|
|
- private readonly List<IAsyncDisposable> disposables = new List<IAsyncDisposable>();
|
|
|
- private bool disposed;
|
|
|
+ private readonly AsyncLock _gate = new AsyncLock();
|
|
|
+ private readonly List<IAsyncDisposable> _disposables = new List<IAsyncDisposable>();
|
|
|
+ private bool _disposed;
|
|
|
|
|
|
public async Task AddAsync(IAsyncDisposable disposable)
|
|
|
{
|
|
|
if (disposable == null)
|
|
|
throw new ArgumentNullException(nameof(disposable));
|
|
|
|
|
|
- using (await gate.LockAsync().ConfigureAwait(false))
|
|
|
+ var shouldDispose = false;
|
|
|
+
|
|
|
+ using (await _gate.LockAsync().ConfigureAwait(false))
|
|
|
{
|
|
|
- if (disposed)
|
|
|
+ if (_disposed)
|
|
|
{
|
|
|
- await disposable.DisposeAsync().ConfigureAwait(false);
|
|
|
+ shouldDispose = true;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- disposables.Add(disposable);
|
|
|
+ _disposables.Add(disposable);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ if (shouldDispose)
|
|
|
+ {
|
|
|
+ await disposable.DisposeAsync().ConfigureAwait(false);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- public async Task RemoveAsync(IAsyncDisposable disposable)
|
|
|
+ public async Task<bool> RemoveAsync(IAsyncDisposable disposable)
|
|
|
{
|
|
|
if (disposable == null)
|
|
|
throw new ArgumentNullException(nameof(disposable));
|
|
|
|
|
|
- using (await gate.LockAsync().ConfigureAwait(false))
|
|
|
+ var shouldDispose = false;
|
|
|
+
|
|
|
+ using (await _gate.LockAsync().ConfigureAwait(false))
|
|
|
{
|
|
|
- if (!disposables.Remove(disposable))
|
|
|
- throw new InvalidOperationException("Disposable not found.");
|
|
|
+ if (!_disposed && _disposables.Remove(disposable))
|
|
|
+ {
|
|
|
+ shouldDispose = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ if (shouldDispose)
|
|
|
+ {
|
|
|
await disposable.DisposeAsync().ConfigureAwait(false);
|
|
|
}
|
|
|
+
|
|
|
+ return shouldDispose;
|
|
|
}
|
|
|
|
|
|
public async Task DisposeAsync()
|
|
|
{
|
|
|
- using (await gate.LockAsync().ConfigureAwait(false))
|
|
|
+ var disposables = default(IAsyncDisposable[]);
|
|
|
+
|
|
|
+ using (await _gate.LockAsync().ConfigureAwait(false))
|
|
|
{
|
|
|
- if (disposed)
|
|
|
- return;
|
|
|
+ if (!_disposed)
|
|
|
+ {
|
|
|
+ _disposed = true;
|
|
|
|
|
|
- disposed = true;
|
|
|
+ disposables = _disposables.ToArray();
|
|
|
+ _disposables.Clear();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ if (disposables != null)
|
|
|
+ {
|
|
|
var tasks = disposables.Select(disposable => disposable.DisposeAsync());
|
|
|
|
|
|
await Task.WhenAll(tasks);
|