使用IDisposable的接口

时间:2013-03-29 16:15:00

标签: .net design-patterns idisposable

关于IDisposable

我正在创建我期望在大多数时间使用系统资源的界面,但并非总是如此。在我的界面上预测使用包括IDisposable是否明智?

例如,我有一个提供同步的平均接口。

interface IDateTimeProvider : IDisposable
{
    int LeapSeconds {get;set;}
    DateTime LocalNow {get;}
    DateTime UtcNow {get;}
    DateTime GpsNow {get;}
}

class NtpTimeProvider : IDateTimeProvider
{
    // Assume client is setup and ready to use.
    // Obtains time via network resources
    NtpClient client;  

   NtpTimeProvider (int leapSeconds)
   { LeapSeconds = leapSeconds;}

    int LeapSeconds {get;set;}
    DateTime LocalNow {get{return client.Utc};}
    DateTime UtcNow {get{return client.Utc};}
    DateTime GpsNow {get{return client.Utc - TimeSpan.FronSeconds(LeapSeconds);}}
    void Dispose()
    {
        if(client != null) Client.Dispose();
    }
}


class SystemTimeProvider : IDateTimeProvider
{

   SystemTimeProvider (int leapSeconds)
   { LeapSeconds = leapSeconds;}

    int LeapSeconds {get;set;}
    DateTime LocalNow {get{return DateTime.Now};}
    DateTime UtcNow {get{return DateTime.UtcNow };}
    DateTime GpsNow {get{return DateTime.UtcNow - TimeSpan.FronSeconds(LeapSeconds);}}
    void Dispose()
    { //obviously this isn't needed}
}

所以问题是,当我期望大多数实现将使用需要发布的系统资源时,我应该强加IDisposable要求吗?目前我这样做,因为当IDateTimeProvider的用户释放资源和

时更容易
if(myDateTimeProvider is IDisposable) ((IDisposable)myDateTimeProvider).Dispose();

不需要。

3 个答案:

答案 0 :(得分:1)

通常,提供接口的原因是允许程序员将概念的各种实现视为具有相同的行为集。如果仅对碰巧管理系统资源的类实现IDisposable,则会迫使程序员处理该实现细节,从而增加设计的复杂性和脆弱性。

如果对象的有用性到期时,您的应用程序可能会引用非托管资源,那么您应该绝对实现IDisposable接口,以便您的类的使用者可以使用Dispose Pattern来释放这些资源。可预测的方式。

提醒一下Dispose Pattern的原因:

  

在计算机编程中,dispose模式是一种设计模式,用于处理使用自动垃圾收集的运行时环境中的资源清理。处置模式旨在解决的基本问题是,由于垃圾收集环境中的对象具有终结器而不是析构器,因此无法保证在任何确定的时间点都会销毁对象。 dispose模式通过为对象提供一个方法(通常称为Dispose或类似方法)来解决这个问题,该方法释放了对象所持有的任何资源。

http://en.wikipedia.org/wiki/Dispose_pattern

答案 1 :(得分:1)

  

所以问题是,当我期望大多数实现将使用需要发布的系统资源时,我应该强加IDisposable要求吗?

这是有争议的,但框架中有一些示例遵循本指南。一个很好的例子是Stream - 它实现了IDisposable,即使有子类也没有必要这样做。

但是,我要谨慎对待您的用户,除非您确实相当确定几乎所有实现都需要IDisposable,而不仅仅是其中的一部分。

答案 2 :(得分:1)

<$> $ 50,000问题是代码是否会获得实现接口的对象的所有权,而不知道它们的具体类型以及是否需要清理。在可能发生的情况下[最快的例子是IEnumerable.GetEnumerator()IEnumerable<T>.GetEnumerator(),尽管存在许多其他示例],客户端代码必须使用以下两种模式之一:

  • 如果接口类型没有实现IDisposable [与非泛型IEnumerator返回的非泛型IEnumerable的情况一样],那么正确编写的客户端获取对象所有权的代码必须 - 在放弃之前 - 检查实现接口的特定对象是否也恰好实现IDisposable,如果是,则调用其IDisposable.Dispose实现。

  • 如果接口确实实现了IDisposable,那么获得所有权的正确编写的客户端必须 - 在放弃对象之前 - 在对象上调用IDisposable.Dispose,除非它以某种方式知道对象实际上不需要清理。请注意,即使某个对象在其IDisposable.Dispose方法中没有执行任何操作,在许多情况下,无条件地调用它比花费任何重要时间来确定是否需要调用更快。即使只有0.001%的对象实例需要清理,包括IDisposable也不会对客户端代码赋予任何新的义务。相反,它会增加客户端代码履行其义务的可能性,并降低所有对象的成本 - 包括99.999%的实例不需要清理。

如果一个接口不太可能被工厂方法返回,也不会在对象的所有者不知道是否需要清理的任何其他场景中使用,那么接口就不需要实现IDisposable。但是对于可以通过工厂方法返回接口类型的情况,它应该实现IDisposable