there is already a similar question about it but my question is about a class exposed to the client.
public class MyClass : IAsyncDisposable {
public ValueTask DisposeAsync() => DoAsyncStuff();
}
The dispose of this class is asynchronous and an implementation of IDisposable
would block the thread.
public void Dispose() => DisposeAsync().GetAwaiter().GetResult();
If IDisposable
is implemented on the class and the user is in a synchronous context so they use the using
statement: using (var c = new MyClass()) {}
, that would block the thread in the back of the user and I think that's very bad. Instead, I would prefer not to implement IDisposable
and force the user to use this explicit form:
MyClass c;
try { c = new MyClass(); }
finally { c.DisposeAsync().GetAwaiter().GetResult(); }
That's more verbose but at least the user won't have bad surprise.
I didn't included code sample of my library because it's a general question. So what do you think about it and have you ever experienced issues when the Dispose
method was waiting synchronously on a Task
behind your back?
Your reasoning is sound, and in this scenario: yes, I'd only implement IAsyncDisposable
.
As for callers in a sync context: even that explicit form should be actively discouraged. The reality is that async is infectious, and it is pretty normal for code that touches async components to also have to be async. So forcing the caller to use an async context is entirely reasonable, IMO.