Why synchronous IDisposable.Dispose() causes thread deadlocks in asynchronous classes:
If closing a network socket or flushing a buffered stream requires an async I/O call (stream.FlushAsync()), calling .Result inside Dispose() can cause thread pool starvation deadlocks.
The Solution: IAsyncDisposable:
public class AsyncResourceClient : IAsyncDisposable
{
public async ValueTask DisposeAsync()
{
if (_networkStream != null)
{
await _networkStream.FlushAsync();
await _networkStream.DisposeAsync();
}
}
}
// Consumer
await using (var client = new AsyncResourceClient())
{
await client.DoWorkAsync();
}