如何在包含多个一次性对象的类中正确实现 IDispose 和 IAsyncDispose

问题描述 投票:0回答:1

我需要实现一个管理多个资源生命周期的类。这些资源可能有不同的 dipose 模式实现:

  1. 同时使用 IDispose 和 IAsyncDispose 管理资源
  2. 仅使用 IDispose 管理资源
  3. 仅使用 IAsyncDispose 的托管资源
  4. 无需 IDispose 或 IAsyncDispose 的托管资源
  5. 非托管资源

现在的任务是正确处置该类控制下的所有资源,无论是否调用 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);
    }
}
c# .net idisposable iasyncdisposable
1个回答
0
投票

同时使用 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(); 
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.