You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现多资源类的IDispose/IAsyncDispose及抽象基类资源管理

多资源生命周期管理类实现方案

背景需求

需要实现一个管理多资源生命周期的类,涉及的资源释放模式分为以下5类:

  • 同时实现IDisposable和IAsyncDisposable的托管资源
  • 仅实现IDisposable的托管资源
  • 仅实现IAsyncDisposable的托管资源
  • 未实现IDisposable或IAsyncDisposable的托管资源
  • 非托管资源

核心目标:无论调用IDisposable.Dispose()、IAsyncDisposable.DisposeAsync(),甚至完全不调用,都要确保所有被管控的资源被正确释放。

核心问题

  1. 调用Dispose时,如何释放仅实现IAsyncDisposable的资源?
  2. 调用DisposeAsync时,如何释放仅实现IDisposable的资源?

需求延伸

如何将上述释放逻辑封装为抽象基类(如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 =>
        {
            // 同步释放混合资源
            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 =>
        {
            // 异步释放混合资源
            if (disposable is IAsyncDisposable asyncDisposable) await asyncDisposable.DisposeAsync().ConfigureAwait(false);
            // ???
            disposable?.Dispose();
        }).ConfigureAwait(false);
    }
}

解决方案解析

问题1:同步Dispose时处理仅实现IAsyncDisposable的资源

对于仅实现IAsyncDisposable的资源,同步调用时需要阻塞等待异步释放完成,推荐使用.NET标准的GetAwaiter().GetResult()替代自定义的AwaitResult(),避免潜在的线程上下文问题:

asyncDisposable?.DisposeAsync().GetAwaiter().GetResult();

注意:该方式在UI线程可能引发死锁,建议在基类注释中提醒子类避免在UI线程同步调用Dispose()。

问题2:异步DisposeAsync时处理仅实现IDisposable的资源

对于仅实现IDisposable的资源,直接调用其Dispose()即可——同步释放方法本身不涉及异步操作,在异步上下文执行同步方法是安全的,你的初步实现中这部分逻辑无需修改。

完善抽象基类的关键优化

  1. 统一资源注册
    当前两个Manage方法可能导致混合资源被重复注册,合并为一个通用方法自动分类存储:
protected void Manage(object? resource)
{
    if (resource is null) return;
    if (resource is IAsyncDisposable asyncDisposable)
        asyncDisposables.Add(asyncDisposable);
    if (resource is IDisposable disposable)
        disposables.Add(disposable);
}

避免子类重复注册同一资源,确保混合资源在两种释放路径中都能被正确处理。

  1. 非托管资源处理
    添加受保护的虚方法,让子类重写以释放非托管资源,在同步/异步释放逻辑的开头调用:
protected virtual void ReleaseUnmanagedResources() { }

非托管资源无异步释放概念,同步释放即可。

  1. 终结器(Finalizer)
    添加终结器确保未显式调用释放方法时,非托管资源仍能被回收:
~DisposableObject()
{
    ReleaseUnmanagedResources();
    // 终结器中不处理托管资源,此时托管对象可能已被GC回收
}
  1. 避免重复释放
    保留IsDisposed检查逻辑,防止资源被重复释放。

  2. 无释放接口的资源
    这类资源由GC自动回收,基类无需额外处理。

最终完善后的基类代码

public abstract class DisposableObject : IDisposable, IAsyncDisposable
{
    private readonly List<IDisposable> _disposables = new();
    private readonly List<IAsyncDisposable> _asyncDisposables = new();
    public bool IsDisposed { get; private set; }

    public void Dispose()
    {
        DisposeCore();
        GC.SuppressFinalize(this);
    }

    public async ValueTask DisposeAsync()
    {
        await DisposeAsyncCore().ConfigureAwait(false);
        GC.SuppressFinalize(this);
    }

    protected void Manage(object? resource)
    {
        if (resource is null) return;
        
        if (resource is IDisposable disposable)
            _disposables.Add(disposable);
        
        if (resource is IAsyncDisposable asyncDisposable)
            _asyncDisposables.Add(asyncDisposable);
    }

    protected virtual void ReleaseUnmanagedResources() { }

    private void DisposeCore()
    {
        if (IsDisposed) return;
        IsDisposed = true;

        // 先释放非托管资源
        ReleaseUnmanagedResources();

        // 释放仅实现IDisposable的资源(混合资源已在异步集合中处理,跳过)
        foreach (var disposable in _disposables)
        {
            if (disposable is not IAsyncDisposable)
                disposable.Dispose();
        }

        // 同步等待仅实现IAsyncDisposable的资源释放完成
        foreach (var asyncDisposable in _asyncDisposables)
        {
            if (asyncDisposable is IDisposable)
                continue;
            
            asyncDisposable.DisposeAsync().GetAwaiter().GetResult();
        }

        _disposables.Clear();
        _asyncDisposables.Clear();
    }

    private async ValueTask DisposeAsyncCore()
    {
        if (IsDisposed) return;
        IsDisposed = true;

        // 释放非托管资源
        ReleaseUnmanagedResources();

        // 异步释放仅实现IAsyncDisposable的资源
        foreach (var asyncDisposable in _asyncDisposables)
        {
            if (asyncDisposable is not IDisposable)
                await asyncDisposable.DisposeAsync().ConfigureAwait(false);
        }

        // 在异步上下文执行同步释放
        foreach (var disposable in _disposables)
        {
            if (disposable is not IAsyncDisposable)
                disposable.Dispose();
        }

        _disposables.Clear();
        _asyncDisposables.Clear();
    }

    ~DisposableObject()
    {
        ReleaseUnmanagedResources();
    }
}

内容的提问来源于stack exchange,提问作者stv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 09:36:01