System.IDisposable 介面

本文提供此 API 參考文件的補充備註。

介面的主要用途 IDisposable 是釋放 Unmanaged 資源。 垃圾收集行程會在不再使用該物件時,自動釋放配置給 Managed 物件的記憶體。 不過,無法預測何時會發生垃圾收集。 此外,垃圾收集行程不知道 Unmanaged 資源,例如視窗句柄,或開啟檔案和數據流。

Dispose使用這個介面的 方法,明確釋放 Unmanaged 資源與垃圾收集行程。 當不再需要物件時,對象的取用者可以呼叫這個方法。

警告

將介面新增 IDisposable 至現有類別是一項重大變更。 因為類型預先存在的取用者無法呼叫 Dispose,所以您無法確定您的類型所持有的非受控資源將會釋出。

由於當不再需要實例所擁有的資源時,型別的取用者會呼叫 實 IDisposable.Dispose 作,因此您應該將Managed物件包裝在 (建議的替代選項)中 SafeHandle ,或者您應該覆寫 Object.Finalize ,以在取用者忘記呼叫 Dispose時釋放 Unmanaged 資源。

重要

在 .NET Framework 中,C++ 編譯程式支援具決定性的資源處置,而且不允許直接實作 Dispose 方法。

如需如何使用這個介面和 Object.Finalize 方法的詳細討論,請參閱 垃圾收集實作 Dispose 方法 主題。

使用實作 IDisposable 的物件

如果您的應用程式只使用實作 介面的物件 IDisposable ,則當您完成使用物件時,應該呼叫對象的 IDisposable.Dispose 實作。 根據您的程式設計語言,您可以透過下列兩種方式之一來執行此動作:

  • 使用 C# 和 Visual Basic 中的 語句,以及 use F# 中的 語句或using函式等using語言建構。
  • 在區塊中包裝對實作的IDisposable.Disposetry/finally呼叫。

注意

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 區塊

如果您的程式設計語言不支援 using 像是 C# 或 Visual Basic 中的 語句或 F# 中的 語句,或者 use 如果您不想使用它,您可以從 語句的 區塊呼叫 IDisposable.Disposefinallytry/finally 。 下列範例會將 using 上一個範例中的 區塊取代為 try/finally 區塊。

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 ,請參閱 試用...抓住。。。Finally Statementtry-finallytry...finally Expressiontry-finally 語句

實作 IDisposable

如果您的類型直接使用 Unmanaged 資源,或想要自行使用可處置的資源,您應該實 IDisposable 作 。 當您不再需要 實例時,類型的取用者可以呼叫您的 IDisposable.Dispose 實作來釋放資源。 若要處理無法呼叫 Dispose的案例,您應該使用衍生自 SafeHandle 的類別來包裝 Unmanaged 資源,或者您應該覆寫 Object.Finalize 參考型別的 方法。 不論是哪一種情況,您都會使用 Dispose 方法來執行使用 Unmanaged 資源之後所需的任何清除,例如釋放、釋放或重設 Unmanaged 資源。 如需實作 IDisposable.Dispose的詳細資訊,請參閱 Dispose(bool) 方法多載

重要

如果您要定義使用 Unmanaged 資源的基類,而且其具有或可能具有應該處置的子類別,您應該實 IDisposable.Dispose 作 方法並提供 的第二個多載 Dispose,如下一節所述。

IDisposable 和繼承階層

具有可處置子類別的基類必須如下所示實 IDisposable 作。 每當您在任何不是 sealedNotInheritable在 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