Skip to content

Commit 95947da

Browse files
committed
add more extensions for the disposables and add base implementations of a disposable-scope
1 parent c42f794 commit 95947da

5 files changed

Lines changed: 157 additions & 0 deletions

File tree

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using Falko.Common.Sequences;
2+
3+
namespace Falko.Common.Disposables;
4+
5+
public abstract class ElementaryDisposableScope : IDisposableScope
6+
{
7+
private const int IsAlreadyDisposed = 1;
8+
9+
private const int IsNotDisposed = 0;
10+
11+
private Lock _locker = new();
12+
13+
// ReSharper disable InconsistentlySynchronizedField
14+
private Sequence<IAsyncDisposable> _asyncDisposables = new();
15+
16+
private volatile int _disposed = IsNotDisposed;
17+
18+
public void Register(IAsyncDisposable asyncDisposable)
19+
{
20+
if (_disposed == IsAlreadyDisposed)
21+
{
22+
asyncDisposable
23+
.DisposeAsync()
24+
.AsTask()
25+
.Wait();
26+
27+
return;
28+
}
29+
30+
lock (_locker)
31+
{
32+
_asyncDisposables.Add(asyncDisposable);
33+
}
34+
}
35+
36+
public async ValueTask DisposeAsync()
37+
{
38+
var disposed = _disposed;
39+
40+
if (disposed == IsAlreadyDisposed)
41+
{
42+
return;
43+
}
44+
45+
if (Interlocked.CompareExchange(ref _disposed, IsAlreadyDisposed, disposed) == IsAlreadyDisposed)
46+
{
47+
return;
48+
}
49+
50+
try
51+
{
52+
await DisposeAsync(_asyncDisposables);
53+
}
54+
finally
55+
{
56+
_locker = null!;
57+
_asyncDisposables = null!;
58+
}
59+
}
60+
61+
protected abstract ValueTask DisposeAsync(Sequence<IAsyncDisposable> asyncDisposables);
62+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Falko.Common.Sequences;
2+
3+
namespace Falko.Common.Disposables;
4+
5+
public sealed class ForwardDisposableScope : ElementaryDisposableScope
6+
{
7+
protected override async ValueTask DisposeAsync(Sequence<IAsyncDisposable> asyncDisposables)
8+
{
9+
var exceptions = new Sequence<Exception>();
10+
11+
foreach (var asyncDisposable in asyncDisposables)
12+
{
13+
try
14+
{
15+
await asyncDisposable.DisposeAsync();
16+
}
17+
catch (Exception exception)
18+
{
19+
exceptions.Add(exception);
20+
}
21+
}
22+
23+
if (exceptions.Count > 0)
24+
{
25+
throw new AggregateException(exceptions);
26+
}
27+
}
28+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using Falko.Common.Extensions;
2+
using Falko.Common.Sequences;
3+
4+
namespace Falko.Common.Disposables;
5+
6+
public sealed class ParallelDisposableScope : ElementaryDisposableScope
7+
{
8+
protected override ValueTask DisposeAsync(Sequence<IAsyncDisposable> asyncDisposables)
9+
{
10+
return Parallel
11+
.ForEachAsync
12+
(
13+
source: asyncDisposables,
14+
body: static (asyncDisposable, _) => asyncDisposable.DisposeAsync()
15+
)
16+
.AsValueTask();
17+
}
18+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Falko.Common.Sequences;
2+
3+
namespace Falko.Common.Disposables;
4+
5+
public sealed class ReverseDisposableScope : ElementaryDisposableScope
6+
{
7+
protected override async ValueTask DisposeAsync(Sequence<IAsyncDisposable> asyncDisposables)
8+
{
9+
var exceptions = new Sequence<Exception>();
10+
11+
foreach (var asyncDisposable in asyncDisposables.Reverse())
12+
{
13+
try
14+
{
15+
await asyncDisposable.DisposeAsync();
16+
}
17+
catch (Exception exception)
18+
{
19+
exceptions.Add(exception);
20+
}
21+
}
22+
23+
if (exceptions.Count > 0)
24+
{
25+
throw new AggregateException(exceptions);
26+
}
27+
}
28+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Falko.Common.Disposables;
2+
3+
namespace Falko.Common.Extensions;
4+
5+
public static partial class DisposableScopeExtensions
6+
{
7+
public static void Register(this IRegisterOnlyDisposableScope scope, IDisposable disposable)
8+
{
9+
scope.Register(new AsyncDisposableWrapper(disposable));
10+
}
11+
}
12+
13+
file sealed class AsyncDisposableWrapper(IDisposable disposable) : IAsyncDisposable
14+
{
15+
public ValueTask DisposeAsync()
16+
{
17+
disposable.Dispose();
18+
19+
return ValueTask.CompletedTask;
20+
}
21+
}

0 commit comments

Comments
 (0)