将 IDisposable(一次性模式)实现为服务(class 成员)
Implementing IDisposable (the Disposable Pattern) as a service (class member)
一次性模式是在每个 class 基础上重新实现的模式。所以,我一直在寻找一种方法来概括它。几年前我 运行 遇到的问题是,即使你将它实现为 class 本身,你也不能从 Disposable 实现和另一个 class 派生对象(C# 不支持多重继承)。
问题是,如何制定通用方法来实现一次性模式,这样您就不需要根据实现 IDisposable 的 class 显式编写它?
这是由 Visual Studio (VS 2015) 为您生成的标准一次性模式。
public class TestClass : IDisposable {
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing) {
if (!disposedValue) {
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.
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~DisposeTest() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// This code added to correctly implement the disposable pattern.
public void Dispose() {
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
#endregion
}
我的实现
所以,这是我想出的解决方案。
public class DisposeService<T> where T : IDisposable {
private readonly T _disposee;
public Action<T> ManagedAction { get; set; }
public Action<T> UnmanagedAction { get; set; }
public DisposeService(T disposee, Action<T> managedAction = null, Action<T> unmanagedAction = null) {
_disposee = disposee;
ManagedAction = managedAction;
UnmanagedAction = unmanagedAction;
}
private bool _isDisposed;
public void Dispose(bool isDisposing) {
if (_isDisposed) return;
if (isDisposing && ManagedAction != null) {
ManagedAction(_disposee);
}
var hasUnmanagedAction = UnmanagedAction != null;
if (hasUnmanagedAction) {
UnmanagedAction(_disposee);
}
_isDisposed = true;
if (isDisposing && hasUnmanagedAction) {
GC.SuppressFinalize(_disposee);
}
}
}
此 class 允许您为实现 IDisposable 的 class 创建 DisposableService<> 成员。下面是一个关于如何在只有托管资源时使用它的示例。
public class TestClass : IDisposable {
protected readonly DisposeService<TestClass> DisposeService;
private readonly SafeHandle _handle;
public TestClass() {
DisposeService = new DisposeService<TestClass>(this, ps => { if (_handle != null) _handle.Dispose(); });
_handle = new SafeFileHandle(IntPtr.Zero, true);
}
public void Dispose() {
DisposeService.Dispose(true);
}
}
工作原理
- DisposeService 将 运行 在您对象的 Dispose 上进行 Dispose。
- DisposeService 的处置将 运行 您在初始化时提供的托管和非托管操作(或在派生 classes 中更新)。
- 如果提供了 UnmanagedAction,GC.SuppressFinalize 将自动 运行。
- 始终确保创建 DisposableService<> 作为构造函数的第一个操作。
所以,这里是一个将此服务与非托管资源一起使用的示例。
public class TestClass : IDisposable {
protected readonly DisposeService<TestClass> DisposeService;
private readonly SafeHandle _handle;
public TestClass() {
DisposeService = new DisposeService<TestClass>(this,
ps => { if (_handle != null) _handle.Dispose(); },
ps => { /* Free unmanaged resources here */ });
_handle = new SafeFileHandle(IntPtr.Zero, true);
}
public void Dispose() {
DisposeService.Dispose(true);
}
~TestClass() {
DisposeService.Dispose(false);
}
}
还有一个从上面的 class 派生 class 的例子。
public class TestClassDerived : TestClass, IDisposable {
private readonly SafeHandle _derivedHandle;
public TestClassDerived() {
// Copy the delegate for the base's managed dispose action.
var baseAction = DisposeService.ManagedAction;
// Update the managed action with new disposes, while still calling the base's disposes.
DisposeService.ManagedAction = ps => {
if (_derivedHandle != null) {
_derivedHandle.Dispose();
}
baseAction(ps);
};
_derivedHandle = new SafeFileHandle(IntPtr.Zero, true);
}
}
简单的柠檬汁。您保留对基委托的引用并将其作为派生 class 委托的一部分进行调用。
总的来说,应该比管理 Microsoft 自 2005 年以来一直提供的 blarg 程序区域更清洁...
编辑: 我认为在构造函数中传递的 'this' 可能是一个问题。但是,它似乎不是:Is it a bad practice to pass "this" as an argument? 请记住在您的操作中进行空检查,这样您就不会尝试处置空值。 :-)
一次性模式是在每个 class 基础上重新实现的模式。所以,我一直在寻找一种方法来概括它。几年前我 运行 遇到的问题是,即使你将它实现为 class 本身,你也不能从 Disposable 实现和另一个 class 派生对象(C# 不支持多重继承)。
问题是,如何制定通用方法来实现一次性模式,这样您就不需要根据实现 IDisposable 的 class 显式编写它?
这是由 Visual Studio (VS 2015) 为您生成的标准一次性模式。
public class TestClass : IDisposable {
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing) {
if (!disposedValue) {
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.
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~DisposeTest() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// This code added to correctly implement the disposable pattern.
public void Dispose() {
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
#endregion
}
我的实现
所以,这是我想出的解决方案。
public class DisposeService<T> where T : IDisposable {
private readonly T _disposee;
public Action<T> ManagedAction { get; set; }
public Action<T> UnmanagedAction { get; set; }
public DisposeService(T disposee, Action<T> managedAction = null, Action<T> unmanagedAction = null) {
_disposee = disposee;
ManagedAction = managedAction;
UnmanagedAction = unmanagedAction;
}
private bool _isDisposed;
public void Dispose(bool isDisposing) {
if (_isDisposed) return;
if (isDisposing && ManagedAction != null) {
ManagedAction(_disposee);
}
var hasUnmanagedAction = UnmanagedAction != null;
if (hasUnmanagedAction) {
UnmanagedAction(_disposee);
}
_isDisposed = true;
if (isDisposing && hasUnmanagedAction) {
GC.SuppressFinalize(_disposee);
}
}
}
此 class 允许您为实现 IDisposable 的 class 创建 DisposableService<> 成员。下面是一个关于如何在只有托管资源时使用它的示例。
public class TestClass : IDisposable {
protected readonly DisposeService<TestClass> DisposeService;
private readonly SafeHandle _handle;
public TestClass() {
DisposeService = new DisposeService<TestClass>(this, ps => { if (_handle != null) _handle.Dispose(); });
_handle = new SafeFileHandle(IntPtr.Zero, true);
}
public void Dispose() {
DisposeService.Dispose(true);
}
}
工作原理
- DisposeService 将 运行 在您对象的 Dispose 上进行 Dispose。
- DisposeService 的处置将 运行 您在初始化时提供的托管和非托管操作(或在派生 classes 中更新)。
- 如果提供了 UnmanagedAction,GC.SuppressFinalize 将自动 运行。
- 始终确保创建 DisposableService<> 作为构造函数的第一个操作。
所以,这里是一个将此服务与非托管资源一起使用的示例。
public class TestClass : IDisposable {
protected readonly DisposeService<TestClass> DisposeService;
private readonly SafeHandle _handle;
public TestClass() {
DisposeService = new DisposeService<TestClass>(this,
ps => { if (_handle != null) _handle.Dispose(); },
ps => { /* Free unmanaged resources here */ });
_handle = new SafeFileHandle(IntPtr.Zero, true);
}
public void Dispose() {
DisposeService.Dispose(true);
}
~TestClass() {
DisposeService.Dispose(false);
}
}
还有一个从上面的 class 派生 class 的例子。
public class TestClassDerived : TestClass, IDisposable {
private readonly SafeHandle _derivedHandle;
public TestClassDerived() {
// Copy the delegate for the base's managed dispose action.
var baseAction = DisposeService.ManagedAction;
// Update the managed action with new disposes, while still calling the base's disposes.
DisposeService.ManagedAction = ps => {
if (_derivedHandle != null) {
_derivedHandle.Dispose();
}
baseAction(ps);
};
_derivedHandle = new SafeFileHandle(IntPtr.Zero, true);
}
}
简单的柠檬汁。您保留对基委托的引用并将其作为派生 class 委托的一部分进行调用。
总的来说,应该比管理 Microsoft 自 2005 年以来一直提供的 blarg 程序区域更清洁...
编辑: 我认为在构造函数中传递的 'this' 可能是一个问题。但是,它似乎不是:Is it a bad practice to pass "this" as an argument? 请记住在您的操作中进行空检查,这样您就不会尝试处置空值。 :-)