IDisposable.Dispose()方法会自动调用吗?

66

可能重复问题:
垃圾回收器会为我调用IDisposable.Dispose()吗?

我有一个类,它具有一些非托管资源。我的类实现了IDisposable接口,在Dispose()方法中释放非托管资源。我必须调用Dispose()方法吗?还是它会自动被调用?垃圾回收器会调用它吗?

4个回答

80

Dispose()方法不会自动调用。如果存在终结器,则它将被自动调用。实现IDisposable接口提供了一种让类的用户提前释放资源的方式,而不必等待垃圾回收器。

客户端首选的方法是使用using语句,即使有异常也可以处理自动调用Dispose()

一个正确的IDisposable实现应该如下:

class MyClass : IDisposable
{
  private bool disposed = false;

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

  protected virtual void Dispose(bool disposing)
  {
    if(!disposed)
    {
      if(disposing)
      {
        // Manual release of managed resources.
      }
      // Release unmanaged resources.
      disposed = true;
    }
  }

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

如果类的用户调用了 Dispose(),则直接进行清理。如果对象被垃圾回收器捕获,则调用 Dispose(false) 进行清理。请注意,当从终结器(~MyClass 方法)调用时,托管引用可能无效,因此只能释放非托管资源。


1
一个迟加入的说明:当引用超出作用范围时,并不会立即调用终结器,而是在垃圾回收过程中“某个时间(可能很久)”后才会调用。因此,请不要依赖终结器进行清理 - Hans Kesting
2
听起来你是在说如果存在终结器,Dispose方法会自动调用(即使终结器没有调用Dispose方法)。但是,除非你显式地编写终结器调用Dispose方法,否则显式终结器不会自动调用Dispose方法,对吗? - Developer Webs
1
“void Dispose()” 应该改为 “public void Dispose()”,这样是否更合适?如果我省略了 public,编译器会报错...或许自2011年以来有所变化。 我可以编辑您的帖子并修复吗? - Luca

11

你需要手动调用这个方法,可能是在一个类似下面的结构中(假设"MyClass"实现了"IDisposable")

using(var myclass = new MyClass())
{
   // do something with myclass
}

// now 'myclass'is Disposed

C# 8.0中,你可以写如下语句:

using var myclass=new MyClass();

而 "myclass" 将在作用域结束时自动释放。

using 语句的优点(与显式调用 Dispose() 相比)是无论您如何退出此块,都将调用 Dispose():通过运行到结尾、遇到 return 语句或抛出异常。


11

如果您在using语句中实例化对象,则在代码退出using块时,将自动调用Dispose()方法。

using(var myObject = new MyDisposableObject())
{
  blah();
} // Dispose() is called here (or whenever the code exits the block)
如果你不使用 using,那么显式调用 Dispose() 就由你(调用代码)来处理对象的释放。
此外,如果你(MyObject 的实现者)的调用者没有调用 Dispose(),你可以添加对终结器的支持。更多信息请参见此处

9
为了确保资源被正确释放,你需要实现IDisposable接口并在析构函数(finalizer)中调用Dispose方法。
class Foo : IDisposable
{
    private bool m_disposed = false;

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

    ~Foo()
    {
        Dispose(false);
    }

    protected void Dispose(bool disposing)
    {
        if (!m_disposed)
        {
            if (disposing)
            { 
                //release managed resources
            }
            //release unmanaged resources

            m_disposed = true;
        }
    }
}

为什么要使用 m_ 前缀? - Kyle Delaney
6
我曾几年前使用 m_ 作为私有成员的前缀...现在我使用 _ 作为前缀。m 代表 member(成员)。 - Cheng Chen

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