
不能只实现 IAsyncDisposable 就完事——必须同步实现 IDisposable,否则在依赖注入或传统 using 场景下会静默泄漏资源。
为什么 DisposeAsync 不能替代 Dispose
因为 .NET 的资源管理生态是混合的:IServiceProvider 在容器释放时会同时检查 IDisposable 和 IAsyncDisposable,但只调用它“看到”的那个;而很多老代码、工具类、测试框架仍只认 Dispose()。如果只实现 IAsyncDisposable,Dispose() 是空的,await using 能走通,但 using (var x = new X()) 或 DI 容器销毁阶段就完全跳过清理逻辑。
常见错误现象:DatabaseResource 关闭连接的 await CloseConnectionAsync() 从不执行,连接池缓慢耗尽,日志里也无异常。
- 必须同时实现两个接口:显式声明
class DatabaseResource : IDisposable, IAsyncDisposable -
Dispose()里不能await,但可以触发同步回退逻辑(例如标记已处置、关闭同步句柄) -
DisposeAsync()应调用Dispose()做同步清理,再异步释放 I/O 级资源
await using 的实际行为和限制
await using 是 C# 8+ 对 IAsyncDisposable 的语法糖,但它只在方法体结束时自动调用 DisposeAsync(),且该调用**必须被 await**——编译器会帮你加 await,但前提是整个方法是 async 的。如果写在一个普通方法里,直接报错 CS8400:“await using 语句需要异步方法上下文”。
使用场景:适合长期存活、需异步释放的资源,比如数据库连接、HTTP 客户端、文件流、gRPC 通道。
- 正确写法:
async Task ProcessAsync() { await using var db = new DatabaseResource(); ... } - 错误写法:
void Process() { await using var db = new DatabaseResource(); ... }→ 编译失败 - 别指望
await using自动处理异常路径外的提前退出;它仍依赖try/finally语义,只是 finally 块里调的是DisposeAsync()
DisposeAsyncCore 模式为什么推荐
微软官方文档建议非密封类定义 protected virtual ValueTask DisposeAsyncCore(),并让 DisposeAsync() 委托给它。这不是强制,但能解决两个关键问题:继承时的可重写性 + 同步/异步双路径复用。
参数差异:没有参数;返回 ValueTask(比 Task 更轻量,适合短时异步操作);必须标记 virtual 才能被子类重写。
- 基类中
DisposeAsync()负责状态检查、标记_disposed = true、调用DisposeAsyncCore() - 子类重写
DisposeAsyncCore(),专注异步清理逻辑,不用重复写幂等判断 - 若子类还需同步释放(如释放
SafeHandle),可在Dispose()中调用相同清理步骤,或仅调用基类Dispose()
容易被忽略的线程与上下文陷阱
DisposeAsync() 默认可能捕获当前同步上下文(比如 ASP.NET Core 请求上下文或 WinForms UI 线程),这在高并发服务中会导致线程饥饿。而 ConfigureAwait(false) 不是可选项,是必需项。
性能影响:没加 ConfigureAwait(false) 的 await 在服务器端可能引发上下文调度开销,实测 QPS 下降 5%~15%,尤其在短生命周期资源上更明显。
- 所有内部
await都应接.ConfigureAwait(false),包括CloseConnectionAsync().ConfigureAwait(false) - 不要在
DisposeAsync()里访问this成员后又await——对象可能已被外部标记为 disposed,后续访问易抛ObjectDisposedException -
ref struct类型不能出现在async方法中(含DisposeAsync),C# 10+ 编译器会直接报 CS9104
最复杂的点不在写法,而在权衡:什么时候该用 IAsyncDisposable?答案是——当释放动作本身涉及 I/O、网络或文件系统等待,且你无法接受阻塞线程时。其余情况,老老实实写 IDisposable 更安全、更兼容、更易测试。











