实施可iDisposable和iasyncdisposable
假设我有一个不处理任何不受管理资源的非密封班。我需要在处置阶段进行单个异步电话,以进行一些清理。没有其他托管资源可以处理。
据我了解,为了进行异步清理调用,我必须实现IASYNCDISPOSABLE,并使用DispoSeasync()和Disposeasynccore()方法。但是该指南说,当您实施异步处置模式时,您还应该实施处置模式。这一切都很好,但是在Dispose()中我没有什么需要做的。
因此,我的问题是,distose()逻辑是空的还是我需要以同步的方式进行异步清理的操作? (请参阅“如果有什么要去的话”中的代码中的评论)。
public class MyClass : IDisposable, IAsyncDisposable
{
private bool disposed;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public async ValueTask DisposeAsync()
{
await DisposeAsyncCore().ConfigureAwait(false);
Dispose(false);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// What if anything should go here?
}
disposed = true;
}
}
protected virtual async ValueTask DisposeAsyncCore()
{
// Make async cleanup call here e.g. Database.CleanupAsync();
}
}
Say I have a non-sealed class that does not deal with any unmanaged resources. I need to make a single async call during its disposing stage to do some clean up. There are no other managed resources to deal with.
From what I understand, in order to make the async clean up call, I must implement IAsyncDisposable and use the DisposeAsync() and DisposeAsyncCore() methods. But the guidance says that you should also implement the dispose pattern when you implement the async dispose pattern. This is all fine but there's nothing really I need to do in the Dispose().
So my question is, should the Dispose() logic be empty or do I need something to do the async cleanup in a synchronous way? (see comment in code about "What if anything should go here").
public class MyClass : IDisposable, IAsyncDisposable
{
private bool disposed;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public async ValueTask DisposeAsync()
{
await DisposeAsyncCore().ConfigureAwait(false);
Dispose(false);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// What if anything should go here?
}
disposed = true;
}
}
protected virtual async ValueTask DisposeAsyncCore()
{
// Make async cleanup call here e.g. Database.CleanupAsync();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
为那些仍然不愿实现这两者的人的示例:
结论
您只能自由添加对异步版本的支持,但要当心:某些包装,例如
foreach
或旧版本的Di容器( ninject , structuremap 等),诸如 retssharp 之类的代码生成器,或诸如 castle.proxy的代理生成器可能不支持iasyncdisposable
。无法将对象投放到iDisposable
将很难捕获您的应用中的错误。而如果您确实实施了它,那么可能发生的最糟糕的事情是僵局,最后阻止(如果您通过Sync-over-Async进行)。通常,最好支持这两个操作,如果您打算公开API,或者您无法控制一生(例如在DI容器或其他知名的包装器中)。
如何
有完整的Microsoft示例,介绍了如何在可继承的类中实现它们两个(非密封,例如在您的示例中) - https://learn.microsoft.com/en-en-us/ dotnet/standard/standard/垃圾收集/实现disposeasync#enasul both-dispose and-asspose-dispose-patterns
Example to those who still hesitate to implement both:
Conclusion
You can freely add support for async version only, but beware: some wraps, like
foreach
or older versions of DI containers (Ninject, StructureMap, etc), code generators like RestSharp, or proxy generators like Castle.Proxy might not supportIAsyncDisposable
. Failing to cast object toIDisposable
will present hard to catch bugs in your app. Whereas if you do implement it, the worst thing that could happen is deadlock in finally block (if you do it through sync-over-async).In general, it is better to support both operations if you plan to make it public API or you don't have control over your class lifetime (like in DI containers or other widely known wrappers).
How to
There is full Microsoft example on how to implement both of them in inheritable class (non-sealed, like in your example) - https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync#implement-both-dispose-and-async-dispose-patterns
处置功能的两种实现都是从呼叫者的角度来看。然后,您的班级将提供两种机制,以消除任何托管和未管理的资源,而呼叫者的应用程序决定选择什么。这也确保了任何无法使用异步模式的消费者不会丢失。
如果您确定或想强制班级的异步消费,则实际上不需要实现同步处置。
因此,根据您对班级使用的愿景,您可以选择如何处置对象。如果您选择保留这两种机制,则可以双向处理所有资源。
Both implementations of dispose feature is from the callers point of view. Your class would then offer both mechanisms to dispose off any managed and unmanaged resources and the caller application decides what to choose. This also ensures that any consumer which is unable to make use of asynchronous patterns are not lost.
You do not really need to implement synchronous dispose if you are sure about or want to force asynchronous consumption of your class.
So depending on your vision of class usage, you can choose how to dispose objects. If you choose to keep both mechanisms, you can dispose all resources both ways.
正如您所说,该课程是未密封的。对于密封的类,足以实现
i(async)一次性
接口。存在一次性
模式存在,因为派生类可能要添加可以同步或异步的清理逻辑。你不知道。这就是为什么您需要实现同步和异步案例的整个模式。对于您的问题。切勿在同步中阻止异步调用
DISPOSE
方法。正确使用班级是呼叫者的责任。如果他决定调用Distose
而不是disposeasync
,并且仅清除同步资源,那是他的决定/错误。如果此异步调用disposeasync
对于适当的清理绝对必要,并且由您控制,请考虑添加同步等效词以在dispose
方法中使用。As you have said, the class is non-sealed. For sealed classes, it's enough to implement
I(Async)Disposable
interface. TheDisposable
pattern exists because the derived class may want to add cleanup logic that can be either sync or async. You can't know. That's why you need to implement the whole pattern for sync and async cases.For your question. Never block async call in sync
Dispose
method. It's a caller's responsibility to use your class correctly. If he decides to callDispose
instead ofDisposeAsync
and clear only sync resources it's his decision/mistake. If this async call inDisposeAsync
is absolutely necessary for proper cleanup and it is controlled by you, consider adding sync equivalent to be used inDispose
method.给任何与我缺乏知识的人的注释...
我遇到了一个相同的问题,我只想实现 iasyncdisposable 在中使用中进行异步HTTP调用>最后要完成的块,但是使用(等待MyAsyncDisposable())错误地使用了同步
。该解决方案正在使用
等待(等待MyAsyncDisposable())
,而IASyncDisposable是唯一需要的iasyncdisposable。A note for anyone with the same lack of knowledge as me...
I had the same issue in which I only wanted to implement IAsyncDisposable to do an asynchronous HTTP call within a
using
block to be done at the end, but was wrongly using the synchronoususing (await MyAsyncDisposable())
. The solution was on usingawait using (await MyAsyncDisposable())
and that way the IAsyncDisposable is the only one needed.