Glossary / IAsyncDisposable

IAsyncDisposable

IAsyncDisposable defines asynchronous cleanup through ValueTask DisposeAsync(). It is appropriate when releasing a resource naturally involves asynchronous work, such as flushing network-backed buffers or completing an asynchronous transaction. Consumers use await using so cleanup is awaited before leaving scope.

Implementation and consumption

await using var stream = new AsyncResource();
await stream.WriteAsync(data);

The compiler ensures disposal is awaited on normal exit, exceptions, and returns. Implementations should release resources once, be safe under the documented repeated-call policy, and avoid synchronization-context deadlocks. ValueTask should generally be awaited once and not stored/reused like a Task unless its contract permits it.

A type can implement both IDisposable and IAsyncDisposable; define how synchronous disposal behaves and whether it can fully release resources without blocking. Libraries should avoid sync-over-async deadlocks and clearly document preferred cleanup. Cancellation tokens are not part of DisposeAsync itself, so resource shutdown should have bounded behavior by design.

Engineering guidance

Use await using for async-owned resources and ensure all owners await disposal. Do not abandon cleanup tasks during shutdown. Test disposal after exceptions and early returns, and verify no resource remains active. Prefer SafeHandle for native handles unless async release is truly required.

Interview questions

  1. Why IAsyncDisposable? Resource cleanup may require asynchronous I/O.
  2. How consume it? await using.
  3. Does it accept a cancellation token? No; DisposeAsync has no token parameter.
  4. Can a type implement both disposal interfaces? Yes, with clear sync/async semantics.
  5. What is a common mistake? Calling async cleanup without awaiting it or blocking synchronously on it.

References