C#IDisposable问题

时间:2010-12-13 17:01:56

标签: c# interface disposable

我有以下代码示例:

public interface IRepository {
   // Whatever
}

public class SampleRepository : IRepository {
   // Implements 'Whatever'
}

public class NHibernateRepository : IRepository, IDisposable {

   // ...

   public void Dispose() { ... }
}

现在 - 真的很糟糕吗?我不确定,但这似乎与C++中没有标记虚拟基类的析构函数相同

我不想让IRepository接口实现IDisposable,因为这会带来不必要的复杂性和一堆类,这些类也必须实现IDisposable


如何处理此案件?

我确信任何类型的层次结构会发生这种情况 - 当其中一个派生类型必须管理可用资源时。

那么我应该怎么做 - 将IDisposable拉到第一个界面或保留它并希望用户区分一次性和非一次性存储库?

谢谢。

6 个答案:

答案 0 :(得分:15)

是的,我会说这很糟糕 - 因为你不能以同样的方式使用所有存储库。

我个人会将存储库接口扩展为IDisposable - 毕竟,使用no-op实现它很容易。

这与主框架中StreamTextReaderTextWriter的选择完全相同。 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对象的引用赋予另一个对象而不转移所有权;在这种情况下,所有者仍然负责在不再需要时处置对象。为此,所有者必须知道不再需要该对象。最常见的模式是:

  1. 将对象作为参数传递给方法;方法返回后,托管该方法的对象将不使用该对象。
  2. 该对象作为参数传递给一个方法,该方法将它存储在某个对象的字段中,但稍后可能会以某种方式请求该对象销毁该引用。
  3. 将一次性作为参数传递给一个方法,该方法由一次性对象的所有者拥有所有引用的对象托管;除非请求,托管对象将不使用一次性对象,并且一次性对象的所有者将知道它是否将永远不再发出此类请求。

如果其中一种模式适用,您可能会处于良好状态。如果不是,你可能遇到麻烦。

答案 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以查看更详细的示例。