IAsyncDisposable是否有参考实现?

时间:2019-09-26 08:34:44

标签: c# .net .net-core idisposable

IDisposable中,我经常使用抽象基类,因为实现它是如此困难。主要是因为您可以使用该界面来处理托管引用和非托管引用,并且每个引用都以不同的方式处理。

public abstract class Disposable : IDisposable
{
    ~Disposable() => this.Dispose(false);

    public bool IsDisposed { get; private set; }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void DisposeManaged() {}
    protected virtual void DisposeUnmanaged() {}

    protected void ThrowIfDisposed()
    {
        if (this.IsDisposed)
        {
            throw new ObjectDisposedException(this.GetType().Name);
        }
    }

    private void Dispose(bool disposing)
    {
        if (!this.IsDisposed)
        {
            if (disposing)
            {
                this.DisposeManaged();
            }

            this.DisposeUnmanaged();
            this.IsDisposed = true;
        }
    }
}

对于IAsyncDisposable,我找不到参考实现。另外,我认为它仅处理托管资源,主要是因为它太新了,并且没有需要处理的非托管资源。它是否正确?如果是这样,那么实现就很简单了吗?

2 个答案:

答案 0 :(得分:2)

我们为框架决定并将在Framework Design Guidelines, 3rd Edition中发布的模式是:

public async ValueTask DisposeAsync()
{
    await DisposeAsyncCore().ConfigureAwait(false);
    Dispose(false);
    GC.SuppressFinalize(this);
}

protected virtual ValueTask DisposeAsyncCore()
{
    // Code goes here that is the async equivalent to Dispose(true)
}

当然,这确实意味着所有IAsyncDisposable类型也是IDisposable。此外,sealed类型可以跳过DisposeAsyncCore()

答案 1 :(得分:1)

与常规Dispose不同,DisposeAsync方法不应从终结器中调用。终结器已经在专用线程中运行,并且不会阻塞任何内容,因此没有必要。因此,DisposeAsync可以始终处置非托管资源和托管资源,并且您无需实现单独的DisposeAsync(bool disposing)方法。通常,只实现单个DisposeAsync方法就可以了,不管该方法是虚拟的还是不虚拟的(取决于设计类型的性质)。

可以在新的.NET Core类型Utf8JsonWriter的源代码中找到IAsyncDisposable实现的示例:

public async ValueTask DisposeAsync()
{
    if (_stream == null)
    {
        // The conditions are ordered with stream first as that would be the most common mode
        if (_output == null)
        {
            return;
        }
    }

    await FlushAsync().ConfigureAwait(false);
    ResetHelper();

    _stream = null;
    _arrayBufferWriter = null;
    _output = null;
}

基本上,它应该以常规的Disposable模式执行与Dispose(true)相同的操作,但如果可能的话,应异步执行。如果不可能进行异步处理,但是由于某种原因您仍然需要实现此接口,则可以退回到同步处理,然后返回完成的ValueTask,如System.IO.Stream中所述。