【问题标题】:Dispose required if using interface使用接口时需要处理
【发布时间】:2010-09-16 18:44:02
【问题描述】:

假设我有一个MyObject 对象,它有两个接口:IMyContractIDisposable。我在一个方法中有这个代码:

IMyContract blah = new MyObject();
blah.Blah();
return;

这是潜在的内存泄漏,对吧?是不是必须这样:

using (MyObject blah = new MyObject())
{
    blah.Blah();
}
return;

【问题讨论】:

    标签: c# memory-leaks dispose


    【解决方案1】:

    好吧,如果它实现了IDisposable,你确实应该处理它。没有说如果你不这样做会泄露什么 - 或者泄露多长时间 - 但你应该有一个 using 声明来避免它。

    (澄清一下:内存是最少可能泄漏的东西,因为IDisposable 通常是关于非托管资源,例如网络连接等。当然有可能 - 对象可能有在远离 GC 视线的地方分配的一些内存的句柄。任何持有对非托管资源的直接引用的IDisposable 的实现也应该有一个终结器,所以泄漏应该只是暂时的......但是这可能仍然很痛苦。)

    【讨论】:

    • 默认 Object.Finalize() 不检查实例是否为 IDisposable,然后调用 Dispose() 方法吗?
    • @KeithS:“Object.Finalize 默认什么都不做。” msdn.microsoft.com/en-us/library/… 请注意,在 C# 中,您使用析构函数语法 (~ClassName()) 来覆盖 Object.Finalize()
    【解决方案2】:

    您也可以在第一个示例中调用 dispose:

    IMyContract blah = new MyObject();
    blah.Blah();
    ((IDisposable)blah).Dispose();
    return;
    

    不太干净,但有时您必须使用接口。

    另一种可能性是您的接口自己继承 IDisposable。然后你可以使用:

    using (IMyContract blah = new MyObject())
    {
        blah.Blah();
    }
    return;
    

    【讨论】:

    • 请注意,如果Blah 抛出异常,您将不会在第一种情况下到达Dispose 行。
    【解决方案3】:

    如果IDisposableimplemented properly(带有调用Dispose() 而没有SuppressFinalize 的终结器),垃圾收集器最终会得到它。但是,using()try { ... } finally { object.Dispose(); } 相同,它们将确定性地(明确地,尽快地)处置。如果您依赖垃圾收集器,您可能会对处理所需的时间感到惊讶。如果有非托管资源,您可能会很快用完它们,因为它们尚未被释放。

    编辑:我第一次错过了这一点。是的,当您使用MyObject 时,您应该正确使用Dispose()using()。如果您有其他使用该接口的代码,那么您可能会有类似:

    public IMyContract GetInterface()
    {
      using (MyObject obj = new MyObject())
      {
        obj.DoSomething();
        return (IMyContract)obj;
      }
    }
    

    然后代码的其余部分可以使用IMyContract contract = GetInterface();,而不必担心(甚至不知道)应该处理的事情。

    【讨论】:

    • 我不知道您是否有意,但您的回答暗示调用object.Dispose 将确定性地释放内存。根本不是这样。调用 Dispose 确定性地释放该对象使用的所有非托管对象(当然,前提是正确实现了 Dispose 方法),但不会影响垃圾收集堆。
    • 不,你是对的。 GC 将调用终结器(如果它没有被抑制),遵循标准的IDisposable 模式将调用Dispose(true) 以便释放非托管资源。
    【解决方案4】:

    从技术上讲,您不会导致内存泄漏。但是,您最终可能会延长资源的打开时间。

    如果IMyContract 的实现者通常是一次性的(或者可能是一次性的),那么IMyContract 应该从IDisposable 继承。否则,您可以让 MyObject 继承自 IDisposable

    无论哪种方式,对象都应该被释放。

    【讨论】:

      猜你喜欢
      • 2021-04-25
      • 1970-01-01
      • 1970-01-01
      • 2020-06-13
      • 1970-01-01
      • 2017-12-24
      • 1970-01-01
      • 2010-11-07
      • 2017-08-02
      相关资源
      最近更新 更多