这个类是否适合作为IDisposable的有效基类?

8

IDisposable模式实现起来成本很高。在实际处理资源之前,我已经数了17行代码。

最近Eric Lippert写了一篇博客文章提出了一个有趣的观点:任何时候Finalizer执行都是一个bug。我认为这很有道理。如果始终遵循IDisposable模式,Finalizer应该总是被抑制,它永远没有机会运行。如果我们认为Finalizer执行是一种错误,那么是否有必要制定指南强制开发人员从以下抽象类派生并禁止直接实现IDisposable接口呢?

public abstract class AbstractDisaposableBase: IDisposable
{
    ~AbstractDisaposableBase()
    {
        ReportObjectLeak();
        Dispose(false); 
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected abstract void Dispose(bool disposing);

    [Conditional("DEBUG")]
    private void ReportObjectLeak()
    {
        //Debug.Assert(false, "leaked instance");
        //throw new Exception("leaked instance");
    }
}

以下是翻译的结果:

好处很明显:

  1. 实现处理变得易于操作且无误,如下所示:

class MyClass1 : DisablableBase { protected override void Dispose(bool disposing) { //如果disposing==true,则释放托管和非托管资源 } }
  1. 没有被处理的对象会被报告

  2. 始终遵循可处理模式

但是,这样的指南是否存在问题呢?

一个可能的问题是所有可处理的对象都将定义终结器。但由于终结器总是被压制的,因此不应该有任何性能损失。

您有什么想法?


3
我个人遵循这里发布的建议:http://blog.stephencleary.com/2009/08/how-to-implement-idisposable-and.html。在我的软件中,我没有未托管的资源,因此我只实现了`Dispose`方法,而没有使用终结器。 - Dirk
@ Dirk,关键是如果这个指南有效,它将使实现IDisposable变得简单和无误。不再需要其他指南了。尽管有一个“除非你需要它”的原则。顺便问一下,你是我认识的那个Dirk吗? - Xiaoguo Ge
@GeorgePolevoy 但是如果在dispose期间抑制了它的执行,那么就不应该有任何性能损失。我已经修改了终结器以实际调用Dispose(false),使其即使在发布时也有用。 - Xiaoguo Ge
在我看来,如果我们能够使用条件错误指令为开发人员提供编译错误,那么这可能是一个不错的选择。 因此,当开发人员使用类时,除非他已经在代码中正确实现了dispose,否则他将无法构建项目。 您建议的是,在对象未被处理并且即将由GC结束时,在运行时抛出异常。但是如果GC永远不会结束它呢? - netaholic
2
这对您来说将是有趣的内容。由于SafeHandle,您几乎永远不需要使用Dispose模式。 - usr
显示剩余8条评论
2个回答

5

是否有必要制定一项指导方针,强制开发人员从以下抽象类中派生?

不需要,因为C#不支持多重继承。接口描述行为,继承规定"is-a"。如果你强制执行这个规则,会严重限制你的类的面向对象设计。

例如,你不能为非可处理的业务对象引入基类,而派生类却可以。


0
但由于终结器总是被抑制,因此不应该有任何性能损失。 AbstractDisposableBase 子类的实例仍然会参与终结队列管理,因此这将影响性能。

GC.SuppressFinalize()会将其从队列中移除吗? - Xiaoguo Ge
这将会增加运行时需要执行的额外工作,还需要将其添加到队列中。 - Kimi
我可能错了,现在也找不到相关信息了,但我相信GC.SuppressFinalize()不需要做任何事情,只需在对象头中标记一个位标志,表示它不需要被终结。这样做的运行时性能影响可以忽略不计 - 对象永远不会被添加到终结器队列中,因为在收集扫描期间,每个对象都会检查该标志。 - Mike Marynowski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接