处理泄漏的IAsyncDisposable实例的推荐方法是什么?

时间:2019-04-14 16:19:22

标签: c# asynchronous dispose

我已经熟悉了C#8和.NET Core 3.0中计划添加的一些内容,并且不确定实现IAsyncDisposable的正确方法(在撰写本文时) ,此链接实际上没有任何指导。)

特别是,对于一个实例没有被显式处理的情况,我不清楚该怎么办-也就是说,它没有包装在async using(...)中,而.DisposeAsync()没有包装显式调用。

我首先想到的是做与实现IDisposable时相同的事情:

  • 我的DisposeAsync()实现通过DisposeAsync(bool disposing)调用disposing: true
  • 使用调用~MyType()的终结器(使用DisposeAsync(disposing: false)
  • DisposeAsync(bool disposing)实际上释放和/或处置了所有内容,并抑制了disposing == true的最终确定。

我担心的是,没有什么可以等待终结器中DisposeAsync(bool)的结果了,显式地等待终结器似乎真的很危险。

当然“泄漏”似乎也不理想。

为具体起见,下面是一个(简化的)示例类,其中 具有终结器:

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实例是否有任何指导?

1 个答案:

答案 0 :(得分:2)

基于在.NET Core类(例如here)中如何实现的示例以及there的一些建议,我想说的是,当您需要实现IAsyncDisposable时,好的做法是同时实施IAsyncDisposableIDisposable。在这种情况下,IAsyncDisposable仅在需要异步处理的情况下负责显式方案,而IDisposable应该根据一次性模式实践照常执行,并且将服务于所有后备方案,包括那些事情最终敲定。因此,您不需要像DisposeAsync(bool disposing)这样的东西-异步处理不能也不应在终结器中发生。唯一的坏消息是您必须同时支持资源回收的两个路径(同步和异步)。