我有以下代码示例:
public interface IRepository {
// Whatever
}
public class SampleRepository : IRepository {
// Implements 'Whatever'
}
public class NHibernateRepository : IRepository, IDisposable {
// ...
public void Dispose() { ... }
}
现在 - 真的很糟糕吗?我不确定,但这似乎与在C++
中没有标记虚拟基类的析构函数相同
我不想让IRepository
接口实现IDisposable
,因为这会带来不必要的复杂性和一堆类,这些类也必须实现IDisposable
。
如何处理此案件?
我确信任何类型的层次结构会发生这种情况 - 当其中一个派生类型必须管理可用资源时。
那么我应该怎么做 - 将IDisposable
拉到第一个界面或保留它并希望用户区分一次性和非一次性存储库?
谢谢。
答案 0 :(得分:15)
是的,我会说这很糟糕 - 因为你不能以同样的方式使用所有存储库。
我个人会将存储库接口扩展为IDisposable
- 毕竟,使用no-op实现它很容易。
这与主框架中Stream
,TextReader
和TextWriter
的选择完全相同。 StringWriter
(例如)不需要处理任何事情......但TextWriter
仍然是一次性的。
这一切都是因为IDisposable
在某些方面是一个奇怪的界面:它没有向调用者传达提供的东西......它传达的东西是需要的来电者(或至少,强烈鼓励可能出现的问题,如果你不同意的话)。
答案 1 :(得分:9)
您可能遇到的唯一问题是使用某种类型的工厂,控制反转或依赖注入模式/框架。如果您想将对象用作接口,则永远无法执行此操作:
IRepository repo = Factory.GetRepository();
repo.Dispose();
您可能想要引入一个实现IDisposable的INHibernateRepository。因为IDisposable通常是如此低级别的操作,所以使接口实现此接口并没有太大的问题。
答案 2 :(得分:4)
不,不要“拉掉IDisposable”。保持接口原子,简单和独立。
除非您认为IDisposable是IRepository的基本特征(并且SampleRepository显示它不是),否则它们之间不应该有任何推导。
答案 3 :(得分:3)
这对我来说似乎完全没问题。有什么问题?
答案 4 :(得分:3)
你所描述的是一个重要的附带条件是正确的:一个类型的对象已经添加了“IDisposable”到它的基础必须永远不会传递给消费者,消费者可能最终持有或持续对象一段未知的时间。
基本上,IDisposable对象的所有者必须(*)负责处理对象本身,或者将对象交给可以接受并履行责任的新所有者。最初,IDisposable对象通常由其创建者“拥有”,但是交接是常见的。可以将IDispoable对象的引用赋予另一个对象而不转移所有权;在这种情况下,所有者仍然负责在不再需要时处置对象。为此,所有者必须知道不再需要该对象。最常见的模式是:
如果其中一种模式适用,您可能会处于良好状态。如果不是,你可能遇到麻烦。
答案 5 :(得分:2)
首先,回答你的问题。配置模式与C ++析构函数不同。 Dispose
方法旨在处理类 所包含的资源 ,而不是处置 类本身 < /强>
在.NET中不存在将C ++析构函数标记为virtual
的原因,因为引用类型的每个实例都有一个包含运行时类型信息的同步块。使用它,垃圾收集器可以适当地回收正确的内存量。
至于使用IRepository
扩展IDisposable
,这将是一个快速修复,在绝大多数情况下都是可以接受的。我能看到的唯一反对意见是扩展接口将需要所有派生类来实现接口。从表面上看,使用NOP(可能多次)实现接口似乎很容易,但您不应该这样做。但是,我可以提供另一种选择。
相反,请考虑使用实现Dispose Pattern的抽象基类。这将遵循处置模式的“标准”实现的结构。
public abstract class Repository : IDisposable
{
public void Dispose() { Dispose(true); }
protected virtual Dispose(bool disposing) { }
}
public class NHibernateRepository : Repository { /* Impl here, add disposal. */ }
public class TestRepository : Repository { /* Impl with no resources */ }
查看Microsoft编写的Dispose Pattern Guidelines以查看更详细的示例。