该 Dispose
模式是出了名的复杂,尤其是当我们有一个需要在不同层次上处理事物的类的层次结构时。推荐的实现如下,取自 实现一个处置方法 - Microsoft Docs.
using System;
class BaseClass : IDisposable
{
// To detect redundant calls
private bool _disposed = false;
~BaseClass() => Dispose(false);
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// TODO: dispose managed state (managed objects).
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
_disposed = true;
}
}
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
class DerivedClass : BaseClass
{
// To detect redundant calls
private bool _disposed = false;
// Instantiate a SafeHandle instance.
private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// Dispose managed state (managed objects).
_safeHandle?.Dispose();
}
_disposed = true;
// Call base class implementation.
base.Dispose(disposing);
}
}
我不明白的是,在这样的实现中,我们增加一个 _disposed
层次结构中的每一级的字段?相反,我们可以处理好 _disposed
只在层次结构的最上层(直接实现了 IDisposable
而在派生类中不关心它。
类似这样。
using System;
class BaseClass : IDisposable
{
// To detect redundant calls
private bool _disposed = false;
~BaseClass()
{
if (_disposed)
{
return;
}
Dispose(false);
_disposed = true;
}
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
if (_disposed)
{
return;
}
Dispose(true);
GC.SuppressFinalize(this);
_disposed = true;
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// TODO: dispose managed state (managed objects).
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
}
}
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
class DerivedClass : BaseClass
{
// Instantiate a SafeHandle instance.
private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Dispose managed state (managed objects).
_safeHandle?.Dispose();
}
// Call base class implementation.
base.Dispose(disposing);
}
}
这是一个被广泛使用的代码样本 所以肯定有一个很好的理由让它被重复实现。_disposed
在每一级都有,但我就是找不到。
在基类里多了一点代码,但在派生类里就不用担心了,还去掉了一些重复的信息。
我还漏了什么?
编辑一下。
正如@InBetween所说,我的实现有一个缺点,就是如果你需要检查你的对象是否在派生类的一个方法中被处理,你将无法检查它。让我们通过把它变成一个私有集的保护属性来纠正这个问题。
using System;
class BaseClass : IDisposable
{
// To detect redundant calls
protected bool Disposed { get; private set; } = false;
~BaseClass()
{
if (Disposed)
{
return;
}
Dispose(false);
Disposed = true;
}
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
if (Disposed)
{
return;
}
Dispose(true);
GC.SuppressFinalize(this);
Disposed = true;
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// TODO: dispose managed state (managed objects).
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
}
}
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
class DerivedClass : BaseClass
{
// Instantiate a SafeHandle instance.
private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true);
public void DoSomething()
{
if(Disposed)
{
throw new ObjectDisposedException("Cannot access disposed resource");
}
}
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Dispose managed state (managed objects).
_safeHandle?.Dispose();
}
// Call base class implementation.
base.Dispose(disposing);
}
}
原因很简单。在你的实现中,你不能使用 _disposed
的派生类型中,以检查是否有任何方法在对象已经被处置时被调用,并采取必要的行动。在你的实现中,你需要创建你自己的多余的flag isDisposed
的目的;你已经有一个 "免费 "的模式本身按照指南。
虽然可以做一个关于制作 _disposed
protected
.
如果你从一个可抛弃类继承,两个条件之一必须是真的。
你的子类没有引入一个新的一次性资源。在这种情况下,你不需要重写 Dispose
而这个问题是没有意义的。
你的子类引入了一个新的一次性资源。在这种情况下,你要重写 Dispose
,插入自己的处理代码,然后调用 base.Dispose
. 该 _disposed
标志是为了帮助你记住防止你的处置代码执行两次。
您当然可以删除 _disposed
如果你愿意。但你可能并不太在意基类的。_disposed
旗帜,如果它甚至有一个。它担心的是它要处置的东西,而你担心的是你的东西。