Search code examples
c#.netidisposable

Should my library implement both IDisposable and IAsyncDisposable?


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?


Solution

  • 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.