DRY IDisposable Pattern
本文关键字:Pattern IDisposable DRY | 更新日期: 2023-09-27 18:28:26
我的很多类都重复下面的代码来实现IDisposable。这似乎违反了DRY(不要重复自己)原则。我可以通过创建AbstractDisposable
基类来避免一些工作,但如果我需要扩展其他现有对象(假设这些对象本身不是一次性的),这似乎不合适/不会起作用。
另一种选择是使用模板/元语言,在那里我可以为每个类指定托管和非托管资源的列表,并在构建项目时自动生成通用的Dispose Pattern-但到目前为止,我还没有使用过元语言/这对于这种常见的场景来说似乎很极端。
public class SomeDisposableClass : IDisposable
{
IDisposable _something; //a managed resource (unique to this class / here for illustration)
/* ... loads of code unique to this class ... */
#region Dispose Pattern
private bool _disposed = false;
~SomeDisposableClass()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this._disposed)
{
if (disposing)
{
// Dispose managed resources.
if (this._something!=null) this._something.Dispose(); //(unique to this class / here for illustration)
}
// Clean up any unmanaged resources
this._disposed = true;
}
}
#endregion
}
有没有一种好的方法可以在不违反DRY原则的情况下实现合适的Dispose模式?
我尽量避免IDisposable
。问题是,它会在整个代码库中传播。如果一个类有一个可丢弃成员,那么该类也需要实现IDisposable等。
此外,当我们讨论类型层次结构时,IDisposable
也存在问题
如果您认为派生类需要释放资源,那么一种常见的场景是将IDisposable
粘贴到基类甚至接口上。然而,大多数情况下,这只是一个假设,它实际上取决于实际实现是否需要资源清理,从而使接口成为一个泄漏的抽象
如果类真的需要接口,最好只实现它。
但这也有其自身的问题:
某个接口的使用者应该如何知道他得到的具体实例——例如作为构造函数参数——需要处理?他必须明确地检查它。他基本上必须对他收到的每一个非密封类型的每个实例都这样做。
这只是两个例子,表明您最好以这样一种方式设计类,即它们不需要实现IDisposable
。
但是,如果您真的需要实现这个接口,您应该遵循CodeProject文章中描述的一次性设计模式。
它基本上将你的类型分为两个级别:
- 级别0:级别0的类只包含非托管资源,不包含托管资源。这些类需要大多数常见的默认
IDisposable
模式,尽管您不必实现处理托管资源的部分 - 级别1:级别1的类只包含级别0和1的托管资源。这些类只需要
IDisposable
的简化实现,因为它们不包含非托管资源。该实现基本上只是在其级别0和级别1的每个成员及其基类上调用Dispose
我不认为你在这里违反了DRY原则。因为尽管你在每个类中进行处理,但本质上你并没有做同样的事情。,