我正确实施IDisposable吗?

maf*_*afu 28 c# idisposable

这个类使用a StreamWriter并因此实现IDisposable.

public class Foo : IDisposable
{
    private StreamWriter _Writer;

    public Foo (String path)
    {
        // here happens something along the lines of:
        FileStream fileWrite = File.Open (path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
        _Writer = new StreamWriter (fileWrite, new ASCIIEncoding ());
    }

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

    ~Foo()
    {
        Dispose (false);
    }

    protected virtual void Dispose (bool disposing)
    {
        if (_Disposed) {
            return;
        }
        if (disposing) {
            _Writer.Dispose ();
        }
        _Writer = null;
        _Disposed = true;
    }
    private bool _Disposed;
}
Run Code Online (Sandbox Code Playgroud)

}

当前的实施有什么问题吗?即,我是否必须FileStream手动释放底层?被Dispose(bool)正确写入?

Ant*_*nes 39

如果您的类不直接使用非托管资源,则无需使用此广泛版本的IDisposable实现.

一个简单的

 public virtual void Dispose()
 {

     _Writer.Dispose();
 }
Run Code Online (Sandbox Code Playgroud)

就足够了.

如果您的消费者无法处理您的对象,那么它将在没有调用Dispose的情况下正常进行GC,_Writer持有的对象也将是GC并且它将具有终结器,因此它仍然可以正确地清理其非托管资源.

编辑

已经做了由Matt提供的链接和其他人我来,我的答案在这里结束一些研究.原因如下: -

在可继承类上,一次性实现"模式"(我的意思是受保护的虚拟Dispose(bool),SuppressFinalize等marlarky)背后的前提是子类可能保留非托管资源.

但是在现实世界中,我们绝大多数的.NET开发人员都不会在非托管资源附近.如果你必须量化" 可能 ",那么你会想到什么样的.NET编码?

让我们假设我有一个Person类型(为了论证,在其中一个字段中有一个一次性类型,因此应该是一次性的).现在我有继承者Customer,Employee等.如果有人继承了Person并希望拥有一个非托管资源,那么使用这个"模式"来混淆Person类是否合理?

有时候,我们开发人员可能会过度复杂化,试图对所有可能的情况进行编码,而不会使用关于这种情况的相对概率的常识.

如果我们想要直接使用非托管资源,那么敏感模式就会将这样的东西包装在自己的类中,其中完整的"一次性模式"是合理的.因此,在大量的"正常"代码中,我们不必担心所有这些问题.如果我们需要IDisposable,我们可以使用上面的简单模式,是否可继承.

哎呀,很高兴从胸前把它弄下来.;)

  • 只有课程被封存,这才足够. (3认同)
  • @Anthony,这是一个合理的反对意见,但我认为更多的复杂性来自人们以不同的,不可预测的方式实现模式.但你似乎知道自己在做什么,这是你的代码,它取决于你. (2认同)
  • @Matt Howells:未来的维护人员可能期望MS模式可能是使用它的一个很好的理由; 恕我直言,这将是唯一的原因.@Eamon Nerbonne:我不喜欢那种模式; 我认为没有理由认为可继承或继承的类应该直接持有非托管资源,除非基类的唯一原因是持有非托管资源(例如SafeHandle),为什么要提供它呢? (2认同)

Mat*_*lls 16

您不需要Finalize(析构函数)方法,因为您没有任何非托管对象.但是,如果GC.SuppressFinalize从Foo继承的类具有非托管对象,则应该保持调用,因此终结器.

如果你使类密封,那么你知道非托管对象永远不会进入等式,所以没有必要添加protected virtual Dispose(bool)重载,或者GC.SuppressFinalize.

编辑:

@ AnthonyWJones对此的反对意见是,如果你知道子类不会引用非托管对象,那么整体Dispose(bool)GC.SuppressFinalize没有必要.但是,如果是这种情况,你应该真正创建类internal而不是public,并且Dispose()方法应该是virtual.如果您知道自己在做什么,那么请不要遵循Microsoft的建议模式,但在破坏规则之前,您应该了解并理解规则!

  • @Anthony:因为它是IDisposable.Dispose()后置条件的一部分.派生类型负责在调用Dispose(true)时释放托管和非托管资源,如果它执行了该职责(并且您认为它确实如此),那么调用SuppressFinalize是安全的. (2认同)
  • Chris Brumme充满胜利:http://blogs.msdn.com/cbrumme/archive/2004/02/20/77460.aspx (2认同)