System.IDisposable 接口

本文提供了此 API 参考文档的补充说明。

接口的主要 IDisposable 用途是释放非托管资源。 垃圾回收器会在不再使用该对象时自动释放分配给托管对象的内存。 但是,无法预测何时发生垃圾回收。 此外,垃圾回收器不了解非托管资源,例如窗口句柄或打开文件和流。

Dispose使用此接口的方法可以与垃圾回收器一起显式释放非托管资源。 当不再需要对象时,对象的使用者可以调用此方法。

警告

将接口添加到 IDisposable 现有类是一项重大更改。 由于类型预先存在的使用者无法调用 Dispose,因此无法确定将释放类型持有的非托管资源。

IDisposable.Dispose由于当不再需要实例拥有的资源时,由类型使用者调用实现,因此应将托管对象包装在(建议的替代项)中SafeHandle,或者应在使用者忘记调用Dispose的情况下替代Object.Finalize释放非托管资源。

重要

在 .NET Framework 中,C++ 编译器支持确定性资源处置,不允许直接实现 Dispose 该方法。

有关如何使用此接口和 Object.Finalize 方法的详细讨论,请参阅 垃圾回收实现 Dispose 方法 主题。

使用实现 IDisposable 的对象

如果应用只是使用实现 IDisposable 接口的对象,则应在使用完该对象后调用该对象的 IDisposable.Dispose 实现。 根据编程语言,可以通过以下两种方式之一执行此操作:

  • 通过使用语言构造,例如 using C# 和 Visual Basic 中的语句,以及 use F# 中的语句或 using 函数。
  • 通过在块中try/finally包装对实现的IDisposable.Dispose调用。

注意

有关实现 IDisposable 的类型的文档请注意这一事实,并包括调用其 Dispose 实现的提醒。

C#、F# 和 Visual Basic Using 语句

如果你的语言支持 C# 中的 using 语句、Visual Basic 中的 Using 语句或 F# 中的 use 语句等构造,则可以使用它,而不是显式调用IDisposable.Dispose自己。 以下示例在定义一个 WordCount 类时使用此方法来保留有关文件的信息及其单词数。

using System;
using System.IO;
using System.Text.RegularExpressions;

public class WordCount
{
    private String filename = String.Empty;
    private int nWords = 0;
    private String pattern = @"\b\w+\b";

    public WordCount(string filename)
    {
        if (!File.Exists(filename))
            throw new FileNotFoundException("The file does not exist.");

        this.filename = filename;
        string txt = String.Empty;
        using (StreamReader sr = new StreamReader(filename))
        {
            txt = sr.ReadToEnd();
        }
        nWords = Regex.Matches(txt, pattern).Count;
    }

    public string FullName
    { get { return filename; } }

    public string Name
    { get { return Path.GetFileName(filename); } }

    public int Count
    { get { return nWords; } }
}
open System.IO
open System.Text.RegularExpressions

type WordCount(filename) =
    let txt = 
        if File.Exists filename |> not then
            raise (FileNotFoundException "The file does not exist.")

        use sr = new StreamReader(filename)
        sr.ReadToEnd()

    let pattern = @"\b\w+\b"
    
    let nWords = Regex.Matches(txt, pattern).Count

    member _.FullName = filename

    member _.Name = Path.GetFileName filename

    member _.Count = nWords
Imports System.IO
Imports System.Text.RegularExpressions

Public Class WordCount
   Private filename As String
   Private nWords As Integer
   Private pattern As String = "\b\w+\b" 

   Public Sub New(filename As String)
      If Not File.Exists(filename) Then
         Throw New FileNotFoundException("The file does not exist.")
      End If   
      
      Me.filename = filename
      Dim txt As String = String.Empty
      Using sr As New StreamReader(filename)
         txt = sr.ReadToEnd()
      End Using
      nWords = Regex.Matches(txt, pattern).Count
   End Sub
   
   Public ReadOnly Property FullName As String
      Get
         Return filename
      End Get   
   End Property
   
   Public ReadOnly Property Name As String
      Get
         Return Path.GetFileName(filename)
      End Get   
   End Property
   
   Public ReadOnly Property Count As Integer
      Get
         Return nWords
      End Get
   End Property
End Class

using语句(useF# 中的表达式)实际上是语法便利。 在编译时,语言编译器为 try/finally 块实现中间语言(IL)。

有关该语句的详细信息using,请参阅 Using 语句或使用语句主题。

Try/Finally 块

如果编程语言不支持 C# 或 Visual Basic 中的语句或 F# 中的语句等using构造,或者不想使用它,则可以从finally语句块/tryfinally调用IDisposable.Dispose实现。use 以下示例将上一示例中的using块替换为块/tryfinally

using System;
using System.IO;
using System.Text.RegularExpressions;

public class WordCount2
{
    private String filename = String.Empty;
    private int nWords = 0;
    private String pattern = @"\b\w+\b";

    public WordCount2(string filename)
    {
        if (!File.Exists(filename))
            throw new FileNotFoundException("The file does not exist.");

        this.filename = filename;
        string txt = String.Empty;
        StreamReader? sr = null;
        try
        {
            sr = new StreamReader(filename);
            txt = sr.ReadToEnd();
        }
        finally
        {
            if (sr != null) sr.Dispose();
        }
        nWords = Regex.Matches(txt, pattern).Count;
    }

    public string FullName
    { get { return filename; } }

    public string Name
    { get { return Path.GetFileName(filename); } }

    public int Count
    { get { return nWords; } }
}
open System.IO
open System.Text.RegularExpressions

type WordCount2(filename) =
    let txt = 
        if File.Exists filename |> not then
            raise (FileNotFoundException "The file does not exist.")

        let sr = new StreamReader(filename)
        try
            sr.ReadToEnd()
        finally
            sr.Dispose()

    let pattern = @"\b\w+\b"
    
    let nWords = Regex.Matches(txt, pattern).Count

    member _.FullName = filename

    member _.Name = Path.GetFileName filename

    member _.Count = nWords
Imports System.IO
Imports System.Text.RegularExpressions

Public Class WordCount2
   Private filename As String
   Private nWords As Integer
   Private pattern As String = "\b\w+\b" 

   Public Sub New(filename As String)
      If Not File.Exists(filename) Then
         Throw New FileNotFoundException("The file does not exist.")
      End If   
      
      Me.filename = filename
      Dim txt As String = String.Empty
      Dim sr As StreamReader = Nothing
      Try
         sr = New StreamReader(filename)
         txt = sr.ReadToEnd()
      Finally
         If sr IsNot Nothing Then sr.Dispose() 
      End Try
      nWords = Regex.Matches(txt, pattern).Count
   End Sub
   
   Public ReadOnly Property FullName As String
      Get
         Return filename
      End Get   
   End Property
   
   Public ReadOnly Property Name As String
      Get
         Return Path.GetFileName(filename)
      End Get   
   End Property
   
   Public ReadOnly Property Count As Integer
      Get
         Return nWords
      End Get
   End Property
End Class

有关模式的详细信息 try/finally ,请参阅 Try...抓住。。。最后语句最后尝试尝试...finally Expression,或 try-finally 语句

实现 IDisposable

如果类型直接使用非托管资源,或者希望自己使用可释放资源,则应实现 IDisposable 。 当不再需要实例时,类型的 IDisposable.Dispose 使用者可以调用实现来释放资源。 若要处理它们无法调用 Dispose的情况,应使用派生自 SafeHandle 的类来包装非托管资源,或者应重写 Object.Finalize 引用类型的方法。 在任一情况下,都使用 Dispose 该方法执行使用非托管资源(例如释放、释放或重置非托管资源)后所需的任何清理。 有关实现 IDisposable.Dispose的详细信息,请参阅 Dispose(bool) 方法重载

重要

如果要定义使用非托管资源的基类,并且该基类具有或可能具有应释放的子类,则应实现 IDisposable.Dispose 该方法并提供第二个重载 Dispose,如下一部分所述。

IDisposable 和继承层次结构

具有应可释放的子类的基类必须如下所示实现 IDisposable 。 每当在非 sealedNotInheritable Visual Basic 中(在 Visual Basic 中)实现IDisposable的任何类型时,都应使用此模式。

  • 它应提供一个公共的非虚拟 Dispose() 方法和受保护的虚拟 Dispose(Boolean disposing) 方法。
  • 该方法 Dispose() 必须调用 Dispose(true) 并取消最终确定性能。
  • 基类型不应包括任何终结器。

以下代码片段反映了基类的释放模式。 它假定你的类型不会重写 Object.Finalize 该方法。

using System;
using System.IO;
using System.Runtime.InteropServices;

class BaseClass1 : IDisposable
{
    // Flag: Has Dispose already been called?
    bool disposed = false;
    // Instantiate a FileStream instance.
    FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate);

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            fs.Dispose();
            // Free any other managed objects here.
            //
        }

        disposed = true;
    }
}
open System
open System.IO

type BaseClass1() =
    // Flag: Has Dispose already been called?
    let mutable disposed = false

    // Instantiate a FileStream instance.
    let fs = new FileStream("test.txt", FileMode.OpenOrCreate)

    interface IDisposable with
        // Public implementation of Dispose pattern callable by consumers.
        member this.Dispose() =
            this.Dispose true
            GC.SuppressFinalize this

    // Implementation of Dispose pattern.
    abstract Dispose: bool -> unit
    override _.Dispose(disposing) =
        if not disposed then
            if disposing then
                fs.Dispose()
                // Free any other managed objects here.
            disposed <- true
Imports System.IO
Imports System.Runtime.InteropServices

Class BaseClass1 : Implements IDisposable
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   ' Instantiate a FileStream instance.
   Dim fs As FileStream = New FileStream("test.txt", FileMode.OpenOrCreate)

   ' Public implementation of Dispose pattern callable by consumers.
   Public Sub Dispose() _
              Implements IDisposable.Dispose
      Dispose(disposing:=True)
      GC.SuppressFinalize(Me)
   End Sub

   ' Protected implementation of Dispose pattern.
   Protected Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Return

      If disposing Then
         fs.Dispose()
         ' Free any other managed objects here.
         '
      End If

      disposed = True
   End Sub
End Class

如果确实重写该方法 Object.Finalize ,则类应实现以下模式。

using System;

class BaseClass2 : IDisposable
{
    // Flag: Has Dispose already been called?
    bool disposed = false;

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            // Free any other managed objects here.
            //
        }

        // Free any unmanaged objects here.
        //
        disposed = true;
    }

    ~BaseClass2()
    {
        Dispose(disposing: false);
    }
}
open System

type BaseClass2() =
    // Flag: Has Dispose already been called?
    let mutable disposed = false

    interface IDisposable with
        // Public implementation of Dispose pattern callable by consumers.
        member this.Dispose() =
            this.Dispose true
            GC.SuppressFinalize this

    // Implementation of Dispose pattern.
    abstract Dispose: bool -> unit
    override _.Dispose(disposing) =
        if not disposed then
            if disposing then
                // Free any other managed objects here.
                ()

            // Free any unmanaged objects here.
            disposed <- true

    override this.Finalize() =
        this.Dispose false
Class BaseClass : Implements IDisposable
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False

   ' Public implementation of Dispose pattern callable by consumers.
   Public Sub Dispose() _
              Implements IDisposable.Dispose
      Dispose(disposing:=True)
      GC.SuppressFinalize(Me)
   End Sub

   ' Protected implementation of Dispose pattern.
   Protected Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Return

      If disposing Then
         ' Free any other managed objects here.
         '
      End If

      ' Free any unmanaged objects here.
      '
      disposed = True
   End Sub

   Protected Overrides Sub Finalize()
      Dispose(disposing:=False)
   End Sub
End Class

子类应实现以下可释放模式:

  • 它们必须重写 Dispose(Boolean) 并调用基类 Dispose(Boolean) 实现。
  • 如果需要,他们可以提供终结器。 终结器必须调用 Dispose(false)

请注意,派生类本身不实现 IDisposable 接口,也不包括无 Dispose 参数方法。 它们仅重写基类 Dispose(Boolean) 方法。

以下代码片段反映了派生类的释放模式。 它假定你的类型不会重写 Object.Finalize 该方法。

using System;
using System.IO;
using System.Runtime.InteropServices;

class MyDerivedClass : MyBaseClass
{
    // Flag: Has Dispose already been called?
    bool disposed = false;
    // Instantiate a FileStream instance.
    FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate);

    // Protected implementation of Dispose pattern.
    protected override void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            fs.Dispose();
            // Free any other managed objects here.
            //
        }

        // Free any unmanaged objects here.
        //

        disposed = true;
        // Call base class implementation.
        base.Dispose(disposing);
    }
}
open Microsoft.Win32.SafeHandles
open System

type MyDerivedClass() =
    inherit MyBaseClass()
    
    // Flag: Has Dispose already been called?
    let mutable disposed = false
    // Instantiate a FileStream instance.
    let fs = new FileStream("test.txt", FileMode.OpenOrCreate)

    // Implementation of Dispose pattern.
    override _.Dispose(disposing) =
        if not disposed then
            if disposing then
                fs.Dispose()
                // Free any other managed objects here.

            // Free any unmanaged objects here.
            disposed <- true
            // Call base class implementation.
            base.Dispose disposing
Imports System.IO
Imports System.Runtime.InteropServices

Class DerivedClass2 : Inherits BaseClass2
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   ' Instantiate a FileStream instance.
   Dim fs As FileStream = New FileStream("test.txt", FileMode.OpenOrCreate)

   ' Protected implementation of Dispose pattern.
   Protected Overrides Sub Dispose(disposing As Boolean)
      If disposed Then Return

      If disposing Then
         fs.Dispose()
         ' Free any other managed objects here.
         '
      End If

      ' Free any unmanaged objects here.
      '
      disposed = True

      ' Call base class implementation.
      MyBase.Dispose(disposing)
   End Sub
End Class