C# 4.0 与IDisposable的混淆

C# 4.0 与IDisposable的混淆,c#-4.0,idisposable,C# 4.0,Idisposable,我对实现IDisposable的正确方法有一些令人不安的疑问。考虑下面的场景… public class Foo : IDisposable {...} public class Bar : IDisposable { private bool disposed = false; private readonly Foo MyFoo; public Bar() { this.MyFoo = new Foo(); } public Ba

我对实现IDisposable的正确方法有一些令人不安的疑问。考虑下面的场景…

public class Foo : IDisposable {...}

public class Bar : IDisposable {

    private bool disposed = false;
    private readonly Foo MyFoo;

    public Bar() {
        this.MyFoo = new Foo();
    }
    public Bar(Foo foo) {
        this.MyFoo = foo;
    }
    ~Bar() {
        Dispose(false);
    }

    protected virtual void Dispose(bool disposing) {
        if (!this.disposed) {
            if (disposing) {
               if (MyFoo != null) {
                   this.MyFoo.Dispose();
                   this.MyFoo = null;
               }
            }
            this.disposed = true;
        }
    }

    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}
我的问题是:

1) 如果一个类创建了一个一次性对象,它应该在自己的Dispose()方法中调用该对象上的Dispose()方法吗

2) 如果一次性对象作为引用传递给类,该类是否仍应调用该引用对象上的Dispose()方法,还是应将其留给首先创建该对象的类


上面的模式似乎出现了很多(特别是在DI中),但我似乎找不到一个具体的正确方法来构造它。

参考优秀的MSDN文章

1) 如果一个类创建了一个一次性对象,它应该在自己的Dispose()方法中调用该对象上的Dispose()方法吗

是的,应该是这样。否则,也将调用Dispose。但这将使物体的寿命至少增加1代。这是由于类定义中的终结器造成的。请参阅上面的文章链接

2) 如果一次性对象作为引用传递给类,该类是否仍应调用该引用对象上的Dispose()方法,还是应将其留给首先创建该对象的类

调用方(更具体地说是创建实例的类)负责调用Dispose方法

~Bar() {
    Dispose(false);
}
每当您发现自己在编写这样的代码时,请先深吸一口气,然后问“我真的需要终结器吗?”您很少需要终结器,只有在您自己拥有非托管资源时才需要终结器

第一个试金石测试是“终结器是否真的做了任何事情?”如果您遵循代码,这一点很清楚。它调用Dispose(false),并且该代码仅在参数为true时执行某些操作。接下来,您不需要终结器。这是完全正常的,终结器是微软担心的事情。他们编写了包装非托管资源的.NET framework类。文件流、套接字等。最重要的是,SafeHandle类,设计用于包装操作系统句柄。他们有自己的终结器,你不用自己重写

因此,如果没有终结器,代码将完全崩溃为简单而正确的实现,您只需调用自己存储的任何一次性对象的Dispose()方法:

public class Bar : IDisposable {
    private readonly Foo MyFoo;
    public Bar() {
        this.MyFoo = new Foo();
    }
    public void Dispose() {
        MyFoo.Dispose();
    }
}

谢谢,所以,在上面的例子中,Bar应该创建一个标志来指示Foo是在内部创建的还是作为引用传递的?然后,可以在virtual Dispose()方法中使用此标志来调用或不调用MyFoo.Dispose()。实际上,Foo.Dispose应该由Foo本身在内部实现。我是说国旗。在Bar.Dispose中,应调用Foo.Dispose。而且多次调用dispose不应该有任何问题。此外,由于Bar创建了MyFoo,因此MyFoo.Dispose应仅在Bar中调用,而不在任何其他类中调用。在某些情况下,接收实现了
IDisposable
类型的参数的对象将负责对其调用
Dispose
IDisposable
的关键概念是“最后一个离开房间的人请关灯”。在任何给定的时间,都应该能够准确地识别一个负责清理每个
IDisposable
的对象;该责任从其创建者开始,但如果创建者为了其他对象的利益而创建对象,并且不再需要该对象本身,则该责任可能会转移。当该对象来自Factory/DI,并且应该属于一个类时,所有者类应负责调用Dispose。如果对象由多个类共享,并且没有人确定它们是否是最后一个,那么它们如何调用Dispose()??这需要重新考虑。谢谢你,汉斯,非常有用。冒着滥用帮助的风险,您是否对在类中创建的一次性对象(而不是作为引用提供的对象)的处理有任何看法?例如,在类构造函数中?这是您需要自己解决的问题。谁成为对象的“所有者”?您实在负担不起创建Foo对象的其他代码在您使用它之前对其进行处理。其他代码也不知道您何时使用完它。所以,通常的方法是转让所有权,然后你处理它。例如,StreamWriter(Stream)构造函数也是由.NET framework完成的。