我需要实现一个管理多个资源生命周期的类。这些资源可能有不同的 dipose 模式实现:
现在的任务是正确处置该类控制下的所有资源,无论是否调用 IDispose 或 IAsyncDispose(甚至都不调用它们)。
当 IDispose 被调用时,如何仅使用 IAsyncDisposable 来处置资源? 当 IAsyncDispose 被调用时,如何仅使用 IDispose 来处置资源?
如何在抽象基类(例如 DisposableObject)中实现该行为,其中子类仅“注册”其资源,而基类负责处置?
这是我的第一次实施尝试:
public abstract class DisposableObject : IDisposableObject, IAsyncDisposableObject
{
private readonly DisposableCollection<IDisposable?> disposables = new();
private readonly AsyncDisposableCollection<IAsyncDisposable?> asyncDisposables = new();
public async ValueTask DisposeAsync()
{
await this.DisposeAsyncCore().ConfigureAwait(false);
GC.SuppressFinalize(this);
}
public void Dispose()
{
this.DisposeCore();
GC.SuppressFinalize(this);
}
public bool IsDisposed { get; private set; }
bool IAsyncDisposableObject.IsDisposed => this.IsDisposed;
bool IDisposableObject.IsDisposed => this.IsDisposed;
protected void Manage(IDisposable? disposable)
{
this.disposables.Add(disposable);
}
protected void Manage(IAsyncDisposable? asyncDisposable)
{
this.asyncDisposables.Add(asyncDisposable);
}
private void DisposeCore()
{
if (this.IsDisposed) return;
this.IsDisposed = true;
this.disposables.Dispose();
this.asyncDisposables.ForEach(asyncDisposable =>
{
// dispose hybrid resources sync
if (asyncDisposable is IDisposable disposable) disposable.Dispose();
// ???
asyncDisposable?.DisposeAsync().AwaitResult();
});
}
private async ValueTask DisposeAsyncCore()
{
if (this.IsDisposed) return;
this.IsDisposed = true;
await this.asyncDisposables.TryDisposeAsync().ConfigureAwait(false);
await this.disposables.ForEachAsync(async disposable =>
{
// dispose hybrid resources async
if (disposable is IAsyncDisposable asyncDisposable) await asyncDisposable.DisposeAsync().ConfigureAwait(false);
// ???
disposable?.Dispose();
}).ConfigureAwait(false);
}
}
同时使用 IDispose 和 IAsyncDispose 管理资源
这种情况相当罕见,但我建议仅在这种情况下致电
DisposeAsync
。
无需 IDispose 或 IAsyncDispose 的托管资源
在这种情况下你什么都不做。
非托管资源
在这种情况下,正确的解决方案是仅为实现
IDisposable
的非托管资源创建一个包装类。尝试同时支持非托管资源和托管一次性资源是一件愚蠢的事情,增加了相当大的复杂性,却没有任何好处。
现在的任务是正确处置该类控制下的所有资源,无论是否调用 IDispose 或 IAsyncDispose(甚至都不调用它们)。
如果
DisposeAsync
实现支持任意线程的处置,那么这可能是可能的。当然,即使没有调用任何处理,也确保处理(再次)是愚蠢的差事,而且是不可能的。处理非托管资源的包装类将在其终结器中处理该场景。
当 IDispose 被调用时,如何仅使用 IAsyncDisposable 来处置资源?
这是一个棘手的问题。如果实现允许从任何线程调用
DisposeAsync
,那么您可以将其扔到线程池上并阻止它。
当 IAsyncDispose 被调用时,如何仅使用 IDispose 来处置资源?
只需致电
Dispose
?
如何在抽象基类(例如 DisposableObject)中实现该行为,其中子类仅“注册”其资源,而基类负责处置?
你为什么要这样做?在几乎所有的设计场景中,组合都胜过继承。这里绝对是这种情况。
我有一个 Disposables 库,它主要可以满足你的需求。它只是不做时髦的
IDisposable.Dispose
=> IAsyncDisposable.DisposeAsync
的事情,所以你必须自己做:
public sealed class MyDisposableCollection : IDisposable, IAsyncDisposable
{
private readonly CollectionAsyncDisposable _disposables = new();
public bool TryAdd(IAsyncDisposable disposable) => _disposables.TryAdd(disposable);
public bool TryAdd(IDisposable disposable) => _disposables.TryAdd(disposable.ToAsyncDisposable());
public ValueTask DisposeAsync() => _disposables.DisposeAsync();
public void Dispose()
{
Task.Run(async () => await _disposables.DisposeAsync())
.GetAwaiter().GetResult();
}
}