问题描述
Disposable模式是在每个类的基础上重新实现的模式。因此,我一直在寻找一种概括的方法。我几年前遇到的问题是,即使您将其实现为类本身,也无法从Disposable实现和另一个类中都派生一个对象(C#不支持多继承)。
The Disposable pattern is one that is re-implemented on a per class basis. So, I was looking for a way to generalize it. The problem I ran into a few years ago is that, even if you implement it as class itself, you can't have an object derive from both your Disposable implementation and from another class (C# doesn't support multi-inheritance).
问题是,您如何以通用方式实现Disposable模式,因此您无需为每个实现IDisposable的类显式编写它
这是Visual Studio(VS 2015)为您生成的标准一次性模式。
Here is the standard Disposable pattern that is generated for you by 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
}
推荐答案
我的实现
因此,这是我想出的解决方案。
My implementation
So, here is the solution I came up with.
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);
}
}
}
此类可让您创建实现IDisposable的类的DisposableService<>成员。这是一个有关仅在托管资源时如何使用它的示例。
This class allows you to create a DisposableService<> member for your class that implements IDisposable. Here is an example on how to use it when you only have managed resources.
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上运行它。
- DisposeService的dispose将运行您提供的托管和非托管操作。初始化(或在派生类中更新)。
- 如果提供了UnmanagedAction,GC.SuppressFinalize将自动运行。
- 始终确保创建
- The DisposeService will run it's Dispose on your object's Dispose.
- The DisposeService's dispose will run your Managed and Unmanaged Action that you provide on initialization (or update in derived classes).
- The GC.SuppressFinalize will run automatically if an UnmanagedAction is provided.
- Always make sure to create the DisposableService<> as the first action of your constructor.
How it works
因此,这是将服务与非托管资源一起使用的示例。 p>
So, here is an example of using this service with unmanaged resources.
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);
}
}
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);
}
}
轻松榨柠檬。
总的来说,应该更干净一些,然后管理Microsoft一直在使用的blarg的过程区域。自2005年以来提供...
Overall, should be cleaner then managing that procedural region of blarg that Microsoft has been providing since 2005...
编辑:我认为在构造函数中传递的 this可能是一个问题。但是,它似乎不是: 请记住,请在操作中放入null检查,这样就不会尝试处理null的东西。 :-)
I thought the 'this' being passed in the constructor might be a concern. But, it doesn't seem to be: Is it a bad practice to pass "this" as an argument? Just remember to put the null checks in your actions so you don't try to Dispose something that is null. :-)
这篇关于将IDisposable(一次性模式)实现为服务(类成员)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!