为什么推荐的 dispose 模式在层次结构的每一层都添加一个 disposed 字段?
Why does the recommended dispose pattern adds a disposed field at each level of the hierarchy?
众所周知,Dispose
模式很难正确处理,尤其是当我们有一个 class 层次结构需要在不同级别处理事物时。推荐的实现如下,取自 Implement a Dispose method - 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
而在派生的 classes 中不关心它。
像这样:
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
来实现它,但我找不到任何。
基础 class 中的代码稍微多了一点,但在派生 class 中不用担心,并且删除了一些重复的信息。
我还缺少什么?
编辑:
正如@InBetween 正确指出的那样,我的实现的一个缺点是如果您需要检查您的对象是否在派生 class 的一种方法中被处置,您将无法检查它.让我们通过将其设为受保护的 属性 和私有集来纠正该问题。
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
来检查在对象已被处置时是否调用了任何方法并采取必要的操作。在您的实施中,您需要创建自己的冗余标志 isDisposed
,这违背了目的;您已经按照指南从模式本身获得了一个 "for free"。
虽然可以制作一个案例 _disposed
protected
.
如果您继承自一次性 class,两个条件之一必须为真。
您的 subcless 没有引入新的一次性资源。在这种情况下,您不需要覆盖 Dispose
并且问题没有实际意义。
您的子class引入了一种新的一次性资源。在这种情况下,您将覆盖 Dispose
,插入您自己的处理代码,然后调用 base.Dispose
。 _disposed
标志可以帮助您记住防止处理代码执行两次。
如果需要,您当然可以删除 _disposed
。但是你可能不太关心 base class' _disposed
标志,如果它有的话。它担心它在处理什么,你担心你的。
众所周知,Dispose
模式很难正确处理,尤其是当我们有一个 class 层次结构需要在不同级别处理事物时。推荐的实现如下,取自 Implement a Dispose method - 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
而在派生的 classes 中不关心它。
像这样:
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
来实现它,但我找不到任何。
基础 class 中的代码稍微多了一点,但在派生 class 中不用担心,并且删除了一些重复的信息。
我还缺少什么?
编辑:
正如@InBetween 正确指出的那样,我的实现的一个缺点是如果您需要检查您的对象是否在派生 class 的一种方法中被处置,您将无法检查它.让我们通过将其设为受保护的 属性 和私有集来纠正该问题。
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
来检查在对象已被处置时是否调用了任何方法并采取必要的操作。在您的实施中,您需要创建自己的冗余标志 isDisposed
,这违背了目的;您已经按照指南从模式本身获得了一个 "for free"。
虽然可以制作一个案例 _disposed
protected
.
如果您继承自一次性 class,两个条件之一必须为真。
您的 subcless 没有引入新的一次性资源。在这种情况下,您不需要覆盖
Dispose
并且问题没有实际意义。您的子class引入了一种新的一次性资源。在这种情况下,您将覆盖
Dispose
,插入您自己的处理代码,然后调用base.Dispose
。_disposed
标志可以帮助您记住防止处理代码执行两次。
如果需要,您当然可以删除 _disposed
。但是你可能不太关心 base class' _disposed
标志,如果它有的话。它担心它在处理什么,你担心你的。