在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
,我找不到参考实现。另外,我认为它仅处理托管资源,主要是因为它太新了,并且没有需要处理的非托管资源。它是否正确?如果是这样,那么实现就很简单了吗?
答案 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中所述。