处理泄漏的IAsyncDisposable实例的推荐方法是什么? [英] What's the recommended way to deal with leaked IAsyncDisposable instances?
问题描述
我已经熟悉了C#8& C中添加的(计划中的)某些内容..NET Core 3.0,并且不确定实现 IAsyncDisposable (在撰写本文时,此链接实际上没有指导).
I've been familiarizing myself with some of the things (that are planned to be) added in C# 8 & .NET Core 3.0, and am unsure on the correct way to implement IAsyncDisposable (at time of writing, this link has literally no guidance).
特别是,我不清楚在未明确处理实例的情况下该怎么办-也就是说,它没有使用(...)包裹在 async中和
.DisposeAsync()
未被明确调用.
In particular, it is unclear to me what to do in the case when an instance isn't explicitly disposed - that is, it isn't wrapped in an async using(...)
and .DisposeAsync()
isn't explicitly called.
My first thought was to do that same thing I'd do when implementing IDisposable:
- 我的
DisposeAsync()
实现使用dispose:true
调用 - 实现一个终结器(使用
〜MyType()
),该终结器将调用DisposeAsync(dispose:false)
-
DisposeAsync(bool处置)
实际上释放和/或处置所有内容,并在dispose == true
时禁止最终确定.
DisposeAsync(bool dispose)
- My
DisposeAsync()
implementation calls aDisposeAsync(bool disposing)
withdisposing: true
- Implement a finalizer (with
~MyType()
) that callsDisposeAsync(disposing: false)
DisposeAsync(bool disposing)
actually frees and/or disposes everything, and suppresses finalizing ifdisposing == true
.
我担心的是,终结器中没有什么要等待 DisposeAsync(bool)
的结果的,而显式地等待终结器似乎真的很危险.
My concerns are that there's nothing to await the results of DisposeAsync(bool)
in the finalizer, and explicitly waiting in a finalizer seems really really dangerous.
当然,只是泄漏"似乎也不理想.
Of course "just leak" also seems less than ideal.
为具体起见,下面是一个(简化的)示例类,其中 具有终结器:
To make this concrete, here's a (simplified) example class that does have a finalizer:
internal sealed class TestAsyncReader: IAsyncDisposable
{
private bool IsDisposed => Inner == null;
private TextReader Inner;
internal TestAsyncReader(TextReader inner)
{
Inner = inner;
}
// the question is, should this exist?
~TestAsyncReader()
{
DisposeAsync(disposing: false);
}
private ValueTask DisposeAsync(bool disposing)
{
// double dispose is legal, but try and do nothing anyway
if (IsDisposed)
{
return default;
}
// should a finalizer even exist?
if (disposing)
{
GC.SuppressFinalize(this);
}
// in real code some resources explicitly implement IAsyncDisposable,
// but for illustration purposes this code has an interface test
if (Inner is IAsyncDisposable supportsAsync)
{
var ret = supportsAsync.DisposeAsync();
Inner = null;
return ret;
}
// dispose synchronously, which is uninteresting
Inner.Dispose();
Inner = null;
return default;
}
public ValueTask DisposeAsync()
=> DisposeAsync(disposing: true);
}
那么,关于正确处理泄漏的 IAsyncDisposable
实例有什么指导吗?
So, is there any guidance around proper handling of leaked IAsyncDisposable
instances?
推荐答案
基于在.NET Core类中如何实现的示例(例如有,我想说,当您需要实现 IAsyncDisposable
时,好的做法是同时实现 IAsyncDisposable
> IAsyncDisposable 和 IDisposable
.在这种情况下, IAsyncDisposable
仅在需要异步处理的情况下负责显式场景,而 IDisposable
应该根据一次性模式实践照常实现,并且将用于所有后备方案,包括最终确定方案.因此,您不需要像 DisposeAsync(bool dispose)
这样的东西-异步处理不能也不应在终结器中发生.唯一的坏消息是您必须同时支持两种资源回收路径(同步和异步).
Basing on examples of how it's implemented inside .NET Core classes (like here) and some recommendations from there, I'd say that when you need to implement IAsyncDisposable
, the good practice would be to implement both IAsyncDisposable
and IDisposable
. In this case IAsyncDisposable
will be only responsible for explicit scenarios when asyncronus disposal is needed, while IDisposable
is supposed to be implemented as usual according to disposable pattern practices and it's going to serve all fallback scenarios including those when things come to finalization. Thus you don't need to have anything like DisposeAsync(bool disposing)
- the asynchronous disposal cannot and shouldn't happen in a finalizer. The only bad news that you'll have to support both paths for resources reclaiming (synchronous and asynchronous).
这篇关于处理泄漏的IAsyncDisposable实例的推荐方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!