如何实现多资源类的IDispose/IAsyncDispose及抽象基类资源管理
多资源生命周期管理类实现方案
背景需求
需要实现一个管理多资源生命周期的类,涉及的资源释放模式分为以下5类:
- 同时实现
IDisposable和IAsyncDisposable的托管资源 - 仅实现
IDisposable的托管资源 - 仅实现
IAsyncDisposable的托管资源 - 未实现
IDisposable或IAsyncDisposable的托管资源 - 非托管资源
核心目标:无论调用IDisposable.Dispose()、IAsyncDisposable.DisposeAsync(),甚至完全不调用,都要确保所有被管控的资源被正确释放。
核心问题
- 调用
Dispose时,如何释放仅实现IAsyncDisposable的资源? - 调用
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()即可——同步释放方法本身不涉及异步操作,在异步上下文执行同步方法是安全的,你的初步实现中这部分逻辑无需修改。
完善抽象基类的关键优化
- 统一资源注册
当前两个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); }
避免子类重复注册同一资源,确保混合资源在两种释放路径中都能被正确处理。
- 非托管资源处理
添加受保护的虚方法,让子类重写以释放非托管资源,在同步/异步释放逻辑的开头调用:
protected virtual void ReleaseUnmanagedResources() { }
非托管资源无异步释放概念,同步释放即可。
- 终结器(Finalizer)
添加终结器确保未显式调用释放方法时,非托管资源仍能被回收:
~DisposableObject() { ReleaseUnmanagedResources(); // 终结器中不处理托管资源,此时托管对象可能已被GC回收 }
避免重复释放
保留IsDisposed检查逻辑,防止资源被重复释放。无释放接口的资源
这类资源由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
相关产品推荐
相关产品推荐

