确定IDisposable是否应扩展接口或在实现所述接口的类上实现

如何确定是否应该使用IDisposable扩展我的一个接口或在实现我的接口的类上实现IDisposable?

我有一个不需要处理任何外部资源的接口,除了一个特定的实现。 我的选择似乎是:

1)在接口上实现IDisposable,要求所有实现都实现Dispose,即使只是一个空方法。

-要么-

2)仅在需要处理资源的类上实现IDisposable。 这将导致“使用”问题,因为我的对象是从工厂创建的,因此所有上游代码都对接口起作用。 由于接口未绑定到IDisposable,因此“使用”不会看到Dispose方法。 但是,我可以将工厂结果投射到实施中; 然而,这会使消费者意识到实现,从而破坏了接口的目的。

关于最佳实践的任何想法?

如果您希望调用者只能与接口交互,而不是实现,那么您希望接口扩展IDisposable 。 如果没有,他们将需要检查该value is IDisposable ,以确定是否需要处置。

如果负责处理对象的对象知道具体实现,并且只有对象使用接口给它(但不负责处理它),那么考虑第二个选项。

第一个选项的一个很好的例子是IEnumerator 。 许多IEnumerator对象在处理时不需要做任何事情,但有些对象不需要做任何事情,因此接口扩展了IDisposable因为负责该对象的创建/生命周期的对象将(或应该)永远不知道底层实现。

第二个例子就像IComparer ,需要比较的许多对象都是一次性的,但是通过接口使用对象的代码部分不负责它的创建/生命周期,所以它不需要知道是否是那种类型是一次性的。

50,000美元的问题是处置的责任是否会与接口一起传递,或者换句话说,使用实现对象的最后一个实体是否可能不是创建它的实体。

IEnumerator实现IDisposable的一个重要原因是实现对象是由实现IEnumerable.GetEnumerator()对象创建的,但通常由其他对象使用。 实现IEnumerable的对象将知道它返回的东西是否真的需要处理,但无法知道收件人何时完成它。 调用IEnumerable.GetEnumerator()的代码将知道何时完成返回的对象,但无法知道是否需要进行任何清理。 明智的做法是指定调用IEnumerable.GetEnumerator()的代码是必需的,以确保返回的对象在被放弃之前将调用Dispose ; 在许多情况下, Dispose方法不会做任何事情,但无条件地调用保证存在的无操作方法比检查不存在的方法的存在便宜。

如果接口类型的性质使得实现对象是否需要清理以及何时应该进行清理的问题都将由同一实体负责,那么接口就不需要inheritanceIDisposable 。 如果实例将由一个实体创建但最后由另一个实体使用,则inheritanceIDisposable将是明智的。

如果在具体类上实现IDisposable ,并且接口用户知道它可能是Disposable; 你可以做

 IFoo foo = Factory.Create("type"); using(foo as IDisposable){ foo.bar(); } 

如果foo没有实现IDisposable ,则using将相当于using(null) ,这将正常工作。

以下示例程序的输出将是

 Fizz.Bar Fizz.Dispose Buzz.Bar 

示例程序

 using System; internal interface IFoo { void Bar(); } internal class Fizz : IFoo, IDisposable { public void Dispose() { Console.WriteLine("Fizz.Dispose"); } public void Bar() { Console.WriteLine("Fizz.Bar"); } } internal class Buzz : IFoo { public void Bar() { Console.WriteLine("Buzz.Bar"); } } internal static class Factory { public static IFoo Create(string type) { switch (type) { case "fizz": return new Fizz(); case "buzz": return new Buzz(); } return null; } } public class Program { public static void Main(string[] args) { IFoo fizz = Factory.Create("fizz"); IFoo buzz = Factory.Create("buzz"); using (fizz as IDisposable) { fizz.Bar(); } using (buzz as IDisposable) { buzz.Bar(); } Console.ReadLine(); } }