我的库应该同时实现 IDisposable 和 IAsyncDisposable 吗?
Should my library implement both IDisposable and IAsyncDisposable?
已经有一个 但我的问题是关于 class 暴露给客户的。
public class MyClass : IAsyncDisposable {
public ValueTask DisposeAsync() => DoAsyncStuff();
}
此 class 的处理是异步的,IDisposable
的实现会阻塞线程。
public void Dispose() => DisposeAsync().GetAwaiter().GetResult();
如果 IDisposable
在 class 上实现并且用户处于同步上下文中,因此他们使用 using
语句:using (var c = new MyClass()) {}
,这将阻塞线程在用户的背后,我认为这非常糟糕。相反,我宁愿不实施 IDisposable
并强制用户使用这种显式形式:
MyClass c;
try { c = new MyClass(); }
finally { c.DisposeAsync().GetAwaiter().GetResult(); }
虽然比较冗长,但至少用户不会感到意外。
我没有包含我的库的代码示例,因为这是一个一般性问题。那么,当 Dispose
方法在您背后的 Task
上同步等待时,您对此有何看法?
你的推理是合理的,在这种情况下:是的,我只会实施 IAsyncDisposable
。
至于同步上下文中的调用者:即使是这种显式形式也应积极劝阻。事实上,异步具有传染性,接触异步组件的代码也必须是异步的,这很正常。因此强制调用者使用异步上下文是完全合理的,IMO。
已经有一个
public class MyClass : IAsyncDisposable {
public ValueTask DisposeAsync() => DoAsyncStuff();
}
此 class 的处理是异步的,IDisposable
的实现会阻塞线程。
public void Dispose() => DisposeAsync().GetAwaiter().GetResult();
如果 IDisposable
在 class 上实现并且用户处于同步上下文中,因此他们使用 using
语句:using (var c = new MyClass()) {}
,这将阻塞线程在用户的背后,我认为这非常糟糕。相反,我宁愿不实施 IDisposable
并强制用户使用这种显式形式:
MyClass c;
try { c = new MyClass(); }
finally { c.DisposeAsync().GetAwaiter().GetResult(); }
虽然比较冗长,但至少用户不会感到意外。
我没有包含我的库的代码示例,因为这是一个一般性问题。那么,当 Dispose
方法在您背后的 Task
上同步等待时,您对此有何看法?
你的推理是合理的,在这种情况下:是的,我只会实施 IAsyncDisposable
。
至于同步上下文中的调用者:即使是这种显式形式也应积极劝阻。事实上,异步具有传染性,接触异步组件的代码也必须是异步的,这很正常。因此强制调用者使用异步上下文是完全合理的,IMO。