8

我有以下代码示例:

public interface IRepository {
   // Whatever
}

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

public class NHibernateRepository : IRepository, IDisposable {

   // ...

   public void Dispose() { ... }
}

现在——真的很糟糕吗?我不确定,但这似乎与不标记基类 virtual in 的析构函数C++非常相似。

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


这种情况应该如何处理?

我确信这可能发生在任何类型层次结构中 - 当派生类型之一必须管理一次性资源时。

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

谢谢你。

4

6 回答 6

15

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

我个人会扩展存储库接口IDisposable——毕竟,用无操作实现它很容易。

Stream这与,TextReaderTextWriter在主框架中所做的选择完全相同。StringWriter(例如)不需要处理任何东西......但TextWriter仍然是一次性的。

这一切的发生是因为IDisposable在某些方面是一个奇怪的界面:它没有传达提供给调用者的东西......它传达了调用者需要的东西(或者至少,如果你不这样做,强烈鼓励可能出现的问题沿着这个走)。

于 2010-12-13T17:16:58.840 回答
9

您可能遇到的唯一问题是您是否使用某种类型的工厂、控制反转或依赖注入模式/框架。如果您想将对象用作接口,您将永远无法做到这一点:

IRepository repo = Factory.GetRepository();
repo.Dispose();

您可能想要引入一个实现 IDisposable 的 INHibernateRepository。因为 IDisposable 通常是一个低级别的操作,所以让你的接口实现这个接口并不是什么大问题。

于 2010-12-13T17:11:24.090 回答
4

不,不要“拉起 IDisposable”。保持接口的原子性、简单性和独立性。

除非您可以争辩说 IDisposable 是 IRepository 的基本特征(而 SampleRepository 表明它不是),否则两者之间不应该有任何派生关系。

于 2010-12-13T17:05:15.573 回答
3

What you've described is okay with one important proviso: an object of a type which has added 'IDisposable' to its base must never be passed to a consumer which may end up holding or persisting the object for an unknown duration.

Basically, the owner of an IDisposable object must(*) either take care of disposing the object itself, or hand the object off to a new owner which can accept and honor the responsibility. Initially, IDisposable objects are generally "owned" by their creator, but hand-offs are common. A reference to an IDispoable object can be given to another object without transferring ownership; in that scenario, the owner is still responsible for disposing the object when it is no longer needed. For that to happen, the owner has to know the object is no longer needed. The most common patterns are:

  1. The object is passed as a parameter to a method; the object hosting the method will not use the object after the method returns.
  2. The object is passed as a parameter to a method which will store it in some object's field, but that object can later somehow be requested to destroy the reference.
  3. The disposable is passed as a parameter to a method which is hosted by an object to which the owner of the disposable object holds all references; the hosting object won't use the disposable object unless requested to, and the owner of the disposable object will know if it'll never issue any more such requests.

If one of those patterns applies, you may be in good shape. If not you may be in trouble.

于 2010-12-13T18:59:33.477 回答
3

这对我来说似乎很好。有什么问题?

于 2010-12-13T17:04:09.770 回答
2

首先,回答你的问题。dispose 模式与 C++ 析构函数不同。方法Dispose旨在处理类包含的资源,而不是处理类本身

virtual.NET 中不存在将 C++ 析构函数标记为的原因,因为引用类型的每个实例都有一个包含运行时类型信息的同步块。使用它,垃圾收集器可以适当地回收正确的内存量。

至于用 扩展IRepositoryIDisposable这将是一个快速修复,在绝大多数情况下都是可以接受的。我能看到的唯一反对意见是扩展接口将需要所有派生类来实现接口。从表面上看,使用 NOP 实现接口似乎很容易(可能多次),但您不必这样做。但是,我可以提供一个替代方案。

相反,请考虑使用实现 Dispose 模式的抽象基类。这将遵循处置模式的“标准”实现的结构。

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

于 2010-12-13T18:31:27.123 回答