关于c#:IDisposable究竟需要什么?

What exactly is IDisposable needed for?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Proper use of the IDisposable interface

我试图从书本、互联网和StackOverflow上找到我问题的真实答案,但到目前为止没有任何帮助,所以我希望我能准确地说出我的问题,使之有意义。

一般来说,我总是发现如何释放内存的基本用法相同,大致如下所示,我确实理解代码本身:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class MyClass : IDisposable
{
    bool disposed = false;
    public void Dispose()
    {
        if (!disposed)
        {
        Dispose(true);
        GC.SuppressFinalize(this);
        disposed = true;
        }
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
        //free managed ressources
        }
    // free other ressources
    }

    ~MyClass()
    {
        Dispose(false);
    }
}

方法的工作方式是完全有意义的。但现在我的问题是:为什么我们需要可以识别的基类?在这个代码示例中,我们定义了一个名为Dispose()的方法。正如我在任何地方读到的那样,该方法是IDisposable的一部分,但是我们刚刚在MyClass中定义了该方法,如果我们不实现基类IDisposable,这个代码仍然可以工作,或者我错了这个假设吗?

我对C并不完全陌生,但我还有很多东西要学,所以希望有人能引导我走上正确的方向。我查了另一篇文章,但找不到同样的问题,所以如果它确实存在并且回答了我的问题,请引导我到那里,我会删除这篇文章。


你说得对,正如你的析构函数~MyClass调用Dispose一样,似乎不需要IDisposable接口。

但是,Dispose不是只由析构函数调用的。当您希望释放非托管资源时,可以在代码中自己调用它。它是必需的,因为您不知道何时调用析构函数(由垃圾收集器决定)。

最后,当使用using时,会调用IDisposable.Dispose

1
2
3
4
using(MyDisposableClass myObject = new MyDisposableClass())
{
    // My Code
}

相当于:

1
2
3
4
5
6
7
8
9
MyDisposableClass myObject = new MyDisposableClass();
try
{
    // My Code
}
finally
{
    myObject.Dispose();
}


实现IDispose为您提供了一个释放您"持有"的资源的地方,比如流、句柄或数据库连接。

Dispose()是从垃圾收集器调用的,基本上是询问对象:"如果您不再需要某些东西,但我无法确定;现在释放它;清理!"

在某种意义上,类似于C++中的析构函数

不同之处在于,C++析构函数在时间上被立即调用和处理()。

在大多数情况下,您不需要实现它。GC非常聪明,能够在90%的案例中找出如何释放已使用的资源。

但是,例如:释放流使用的内存不会自动关闭流和释放数据库连接也不会关闭它。

实现Dispose允许您在释放对象时关闭文件:

1
2
3
4
5
6
7
8
9
10
11
12
internal class Something : IDisposable {
private Stream stream;

public void SomeMethod() {
    stream.Write("nskdns");
}

public void Dispose() {
    if (stream != null) {
        stream.Close();
    }
}

此外:实现IDispose使您有机会在using语句中使用类:

1
2
3
4
5
6
public void Example() {
    using (var x = new Something())
    {
        x.SomeMethod();
    }
}

确保当GC释放已使用的流时,X总是将其关闭。

但是,我更喜欢类上的专用close()方法来允许显式关闭流,而不是依赖GC和调用Dispose()。


IDisposable.Dispose的实际实现调用Dispose(bool)的基类实现。从此类继承的任何人现在都具有以下任务,如果他们还需要释放:

1
2
3
4
5
public override Dispose(bool disposing)
{
    base.Dispose(disposing);
    //my disposal code
}

使用这种公认的模式,继承者可以在不破坏基类处置的情况下扩展处置代码。

通常,如果您没有要处理的非托管资源,并且能够密封类,则可以使用以下代码简化问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public sealed class SomeDisposable:IDisposable
{
    public void Dispose()
    {
       //just go ahead and clean up
       //because we're sealed, no-one can ever break
       //this code via inheritance
    }
    //~SomeDisposable()
    //{
    //   if this is being called then it will be called
    //   on all referenced and unrooted IDisposables too
    //   If everything is managed, that means we've got nothing
    //   left to clean up, so we can omit this Finalizer
    //}
}


它与c编译器的using块一起使用。