IDisposable 介面

定義

提供用於釋放 Unmanaged 資源的機制。Provides a mechanism for releasing unmanaged resources.

public interface class IDisposable
public interface IDisposable
[System.Runtime.InteropServices.ComVisible(true)]
public interface IDisposable
type IDisposable = interface
[<System.Runtime.InteropServices.ComVisible(true)>]
type IDisposable = interface
Public Interface IDisposable
衍生
屬性

範例

下列範例示範如何建立可執行介面的資源類別 IDisposableThe following example demonstrates how to create a resource class that implements the IDisposable interface.

#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::ComponentModel;
using namespace System::Windows::Forms;

// The following example demonstrates how to create a class that 
// implements the IDisposable interface and the IDisposable.Dispose
// method with finalization to clean up unmanaged resources. 
//
public ref class MyResource: public IDisposable
{
private:

   // Pointer to an external unmanaged resource.
   IntPtr handle;

   // A managed resource this class uses.
   Component^ component;

   // Track whether Dispose has been called.
   bool disposed;

public:
   // The class constructor.
   MyResource( IntPtr handle, Component^ component )
   {
      this->handle = handle;
      this->component = component;
      disposed = false;
   }

   // This method is called if the user explicitly disposes of the
   // object (by calling the Dispose method in other managed languages, 
   // or the destructor in C++). The compiler emits as a call to 
   // GC::SuppressFinalize( this ) for you, so there is no need to 
   // call it here.
   ~MyResource() 
   {
      // Dispose of managed resources.
      component->~Component();

      // Call C++ finalizer to clean up unmanaged resources.
      this->!MyResource();

      // Mark the class as disposed. This flag allows you to throw an
      // exception if a disposed object is accessed.
      disposed = true;
   }

   // Use interop to call the method necessary to clean up the 
   // unmanaged resource.
   //
   [System::Runtime::InteropServices::DllImport("Kernel32")]
   static Boolean CloseHandle( IntPtr handle );

   // The C++ finalizer destructor ensures that unmanaged resources get
   // released if the user releases the object without explicitly 
   // disposing of it.
   //
   !MyResource()
   {      
      // Call the appropriate methods to clean up unmanaged 
      // resources here. If disposing is false when Dispose(bool,
      // disposing) is called, only the following code is executed.
      CloseHandle( handle );
      handle = IntPtr::Zero;
   }

};

void main()
{
   // Insert code here to create and use the MyResource object.
   MyResource^ mr = gcnew MyResource((IntPtr) 42, (Component^) gcnew Button());
   mr->~MyResource();
}
using System;
using System.ComponentModel;

// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.

public class DisposeExample
{
    // A base class that implements IDisposable.
    // By implementing IDisposable, you are announcing that
    // instances of this type allocate scarce resources.
    public class MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource.
        private IntPtr handle;
        // Other managed resource this class uses.
        private Component component = new Component();
        // Track whether Dispose has been called.
        private bool disposed = false;

        // The class constructor.
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the
        // runtime from inside the finalizer and you should not reference
        // other objects. Only unmanaged resources can be disposed.
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if(disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }

                // Call the appropriate methods to clean up
                // unmanaged resources here.
                // If disposing is false,
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;
            }
        }

        // Use interop to call the method necessary
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        // Use C# destructor syntax for finalization code.
        // This destructor will run only if the Dispose method
        // does not get called.
        // It gives your base class the opportunity to finalize.
        // Do not provide destructors in types derived from this class.
        ~MyResource()
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(false) is optimal in terms of
            // readability and maintainability.
            Dispose(false);
        }
    }
    public static void Main()
    {
        // Insert code here to create
        // and use the MyResource object.
    }
}
Imports System.ComponentModel

' The following example demonstrates how to create
' a resource class that implements the IDisposable interface
' and the IDisposable.Dispose method.
Public Class DisposeExample

   ' A class that implements IDisposable.
   ' By implementing IDisposable, you are announcing that 
   ' instances of this type allocate scarce resources.
   Public Class MyResource
      Implements IDisposable
      ' Pointer to an external unmanaged resource.
      Private handle As IntPtr
      ' Other managed resource this class uses.
      Private component As component
      ' Track whether Dispose has been called.
      Private disposed As Boolean = False

      ' The class constructor.
      Public Sub New(ByVal handle As IntPtr)
         Me.handle = handle
      End Sub

      ' Implement IDisposable.
      ' Do not make this method virtual.
      ' A derived class should not be able to override this method.
      Public Overloads Sub Dispose() Implements IDisposable.Dispose
         Dispose(True)
         ' This object will be cleaned up by the Dispose method.
         ' Therefore, you should call GC.SupressFinalize to
         ' take this object off the finalization queue 
         ' and prevent finalization code for this object
         ' from executing a second time.
         GC.SuppressFinalize(Me)
      End Sub

      ' Dispose(bool disposing) executes in two distinct scenarios.
      ' If disposing equals true, the method has been called directly
      ' or indirectly by a user's code. Managed and unmanaged resources
      ' can be disposed.
      ' If disposing equals false, the method has been called by the 
      ' runtime from inside the finalizer and you should not reference 
      ' other objects. Only unmanaged resources can be disposed.
      Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
         ' Check to see if Dispose has already been called.
         If Not Me.disposed Then
            ' If disposing equals true, dispose all managed 
            ' and unmanaged resources.
            If disposing Then
               ' Dispose managed resources.
               component.Dispose()
            End If

            ' Call the appropriate methods to clean up 
            ' unmanaged resources here.
            ' If disposing is false, 
            ' only the following code is executed.
            CloseHandle(handle)
            handle = IntPtr.Zero

            ' Note disposing has been done.
            disposed = True

         End If
      End Sub

      ' Use interop to call the method necessary  
      ' to clean up the unmanaged resource.
      <System.Runtime.InteropServices.DllImport("Kernel32")> _
      Private Shared Function CloseHandle(ByVal handle As IntPtr) As [Boolean]
      End Function

      ' This finalizer will run only if the Dispose method 
      ' does not get called.
      ' It gives your base class the opportunity to finalize.
      ' Do not provide finalize methods in types derived from this class.
      Protected Overrides Sub Finalize()
         ' Do not re-create Dispose clean-up code here.
         ' Calling Dispose(false) is optimal in terms of
         ' readability and maintainability.
         Dispose(False)
         MyBase.Finalize()
      End Sub
   End Class

   Public Shared Sub Main()
      ' Insert code here to create
      ' and use the MyResource object.
   End Sub

End Class

備註

此介面的主要用途是釋放非受控資源。The primary use of this interface is to release unmanaged resources. 當物件不再使用時,垃圾收集行程會自動釋放配置給受管理物件的記憶體。The garbage collector automatically releases the memory allocated to a managed object when that object is no longer used. 不過,您無法預測何時會發生垃圾收集。However, it is not possible to predict when garbage collection will occur. 此外,垃圾收集行程並不知道視窗控制碼、開啟檔案和資料流程等非受控資源。Furthermore, the garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams.

Dispose 可以使用此介面的方法,將未受管理的資源與垃圾收集行程一起明確地發行。Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with the garbage collector. 當不再需要物件時,物件的取用者可以呼叫這個方法。The consumer of an object can call this method when the object is no longer needed.

警告

這是將 IDisposable 介面新增至現有類別的重大變更。It is a breaking change to add the IDisposable interface to an existing class. 因為您類型的預先存在取用者無法呼叫 Dispose ,所以您無法確定您的類型所持有的非受控資源將會被釋放。Because pre-existing consumers of your type cannot call Dispose, you cannot be certain that unmanaged resources held by your type will be released.

因為 IDisposable.Dispose 當您不再需要實例所擁有的資源時,型別的取用者會呼叫此實,所以您應該將 managed 物件包裝在 SafeHandle (建議的替代) 中,否則您應該覆寫, Object.Finalize 以在取用者忘記呼叫的事件中釋放未受管理的資源 DisposeBecause the IDisposable.Dispose implementation is called by the consumer of a type when the resources owned by an instance are no longer needed, you should either wrap the managed object in a SafeHandle (the recommended alternative), or you should override Object.Finalize to free unmanaged resources in the event that the consumer forgets to call Dispose.

重要

在 .NET Framework 中,c + + 編譯器支援決定性的資源處置,而且不允許直接執行 Dispose 方法。In the .NET Framework, the C++ compiler supports deterministic disposal of resources and does not allow direct implementation of the Dispose method.

如需有關如何使用這個介面和方法的詳細討論 Object.Finalize ,請參閱 垃圾收集執行 Dispose 方法 主題。For a detailed discussion about how this interface and the Object.Finalize method are used, see the Garbage Collection and Implementing a Dispose Method topics.

使用可執行 IDisposable 的物件Using an object that implements IDisposable

如果您的應用程式只使用可執行介面的物件 IDisposable ,您應該在使用完畢後呼叫物件的 IDisposable.Dispose 執行。If your app simply uses an object that implements the IDisposable interface, you should call the object's IDisposable.Dispose implementation when you are finished using it. 根據您的程式設計語言,您可以透過下列兩種方式之一來執行此動作:Depending on your programming language, you can do this in one of two ways:

  • 使用語言結構 using ,例如 c # 中的語句和 Visual Basic。By using a language construct such as the using statement in C# and Visual Basic.

  • 藉由 IDisposable.Dispose 在區塊中包裝對實的呼叫 try / finallyBy wrapping the call to the IDisposable.Dispose implementation in a try/finally block.

注意

適用于的型別檔可讓您 IDisposable 注意事實,並包含呼叫其實作為的提示 DisposeDocumentation for types that implement IDisposable note that fact and include a reminder to call its Dispose implementation.

C # 和 Visual Basic Using 語句The C# and Visual Basic Using statement

如果您的語言支援結構,例如 c # 中的 using 語句和 Visual Basic 中的 using 語句,您可以使用它,而不是明確地呼叫它 IDisposable.DisposeIf your language supports a construct such as the using statement in C# and the Using statement in Visual Basic, you can use it instead of explicitly calling IDisposable.Dispose yourself. 下列範例會使用這個方法 WordCount 來定義類別,以保留檔案的相關資訊,以及其中的單字數目。The following example uses this approach in defining a WordCount class that preserves information about a file and the number of words in it.

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; } }
}
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語句實際上是語法的便利性。The using statement is actually a syntactic convenience. 在編譯時期,語言編譯器會針對區塊實 (IL) 的中繼語言 try / finallyAt compile time, the language compiler implements the intermediate language (IL) for a try/finally block.

如需語句的詳細資訊 using ,請參閱 using 語句使用語句 主題。For more information about the using statement, see the Using Statement or using Statement topics.

Try/Finally 區塊The Try/Finally block

如果您的程式設計語言不支援像 using c # 或 Visual Basic 中的語句,或不想使用它,您可以 IDisposable.Dispose 從語句區塊呼叫實作為 finally try / finallyIf your programming language does not support a construct like the using statement in C# or Visual Basic, or if you prefer not to use it, you can call the IDisposable.Dispose implementation from the finally block of a try/finally statement. 下列範例會 using 以區塊取代上一個範例中的區塊 try / finallyThe following example replaces the using block in the previous example with a try/finally block.

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;
      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; } }
}
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
      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 語句try-finallytry-finally 語句For more information about the try/finally pattern, see Try...Catch...Finally Statement, try-finally, or try-finally Statement.

實作 IDisposableImplementing IDisposable

IDisposable只有當您的類型直接使用非受控資源時,才應該執行。You should implement IDisposable only if your type uses unmanaged resources directly. 當不再需要實例時,您類型的取用者可以呼叫您的 IDisposable.Dispose 實作為釋放資源。The consumers of your type can call your IDisposable.Dispose implementation to free resources when the instance is no longer needed. 若要處理無法呼叫它們的情況 Dispose ,您應該使用衍生自的類別 SafeHandle 包裝未受管理的資源,或覆寫 Object.Finalize 參考型別的方法。To handle cases in which they fail to call Dispose, you should either use a class derived from SafeHandle to wrap the unmanaged resources, or you should override the Object.Finalize method for a reference type. 無論是哪一種情況,您都可以使用方法,在 Dispose 使用非受控資源(例如釋出、釋放或重設非受控資源)之後執行任何必要的清除。In either case, you use the Dispose method to perform whatever cleanup is necessary after using the unmanaged resources, such as freeing, releasing, or resetting the unmanaged resources.

重要

如果您要定義的基類使用非受控資源,且其中有(或可能有)應該處置的子類別,您應該執行 IDisposable.Dispose 方法並提供的第二個多載 Dispose ,如下一節所述。If you are defining a base class that uses unmanaged resources and that either has, or is likely to have, subclasses that should be disposed, you should implement the IDisposable.Dispose method and provide a second overload of Dispose, as discussed in the next section.

IDisposable 和繼承階層IDisposable and the inheritance hierarchy

具有應可處置之子類別的基類必須依照 IDisposable 下列方式來執行。A base class with subclasses that should be disposable must implement IDisposable as follows. 當您在 IDisposable 任何未 sealed (于 Visual Basic) 的類型上執行時,您應該使用這個模式 NotInheritableYou should use this pattern whenever you implement IDisposable on any type that isn't sealed (NotInheritable in Visual Basic).

  • 它應該提供一個公用、非虛擬 Dispose() 方法和一個受保護的虛擬 Dispose(Boolean disposing) 方法。It should provide one public, non-virtual Dispose() method and a protected virtual Dispose(Boolean disposing) method.

  • Dispose()方法必須呼叫 Dispose(true) ,且應抑制效能的最終處理。The Dispose() method must call Dispose(true) and should suppress finalization for performance.

  • 基底類型不應該包含任何完成項。The base type should not include any finalizers.

下列程式碼片段會反映基類的處置模式。The following code fragment reflects the dispose pattern for base classes. 它會假設您的型別不會覆寫 Object.Finalize 方法。It assumes that your type does not override the Object.Finalize method.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

class BaseClass : IDisposable
{
   // Flag: Has Dispose already been called?
   bool disposed = false;
   // Instantiate a SafeHandle instance.
   SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);

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

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

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

      disposed = true;
   }
}
Imports Microsoft.Win32.SafeHandles
Imports System.Runtime.InteropServices

Class BaseClass : Implements IDisposable
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   ' Instantiate a SafeHandle instance.
   Dim handle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)

   ' Public implementation of Dispose pattern callable by consumers.
   Public Sub Dispose() _
              Implements IDisposable.Dispose
      Dispose(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
         handle.Dispose()
         ' Free any other managed objects here.
         '
      End If
      
      disposed = True
   End Sub
End Class

如果您確實覆寫 Object.Finalize 方法,您的類別應該會執行下列模式。If you do override the Object.Finalize method, your class should implement the following pattern.

using System;

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

   // Public implementation of Dispose pattern callable by consumers.
   public void Dispose()
   {
      Dispose(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;
   }

   ~BaseClass()
   {
      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(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(False)      
   End Sub
End Class

子類別應實作可處置模式,如下所示:Subclasses should implement the disposable pattern as follows:

  • 它們必須覆寫 Dispose(Boolean) 並呼叫基底類別 Dispose(Boolean) 實作。They must override Dispose(Boolean) and call the base class Dispose(Boolean) implementation.

  • 如有需要,它們可以提供完成項。They can provide a finalizer if needed. 完成項必須呼叫 Dispose(false)The finalizer must call Dispose(false).

請注意,衍生類別本身不會執行 IDisposable 介面,也不會包含無參數 Dispose 方法。Note that derived classes do not themselves implement the IDisposable interface and do not include a parameterless Dispose method. 它們只會覆寫基類 Dispose(Boolean) 方法。They only override the base class Dispose(Boolean) method.

下列程式碼片段會反映衍生類別的處置模式。The following code fragment reflects the dispose pattern for derived classes. 它會假設您的型別不會覆寫 Object.Finalize 方法。It assumes that your type does not override the Object.Finalize method.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

class DerivedClass : BaseClass
{
   // Flag: Has Dispose already been called?
   bool disposed = false;
   // Instantiate a SafeHandle instance.
   SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);

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

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

      // Free any unmanaged objects here.
      //

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

Class DerivedClass : Inherits BaseClass 
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   ' Instantiate a SafeHandle instance.
   Dim handle As SafeHandle = New SafeFileHandle(IntPtr.Zero, True)

   ' Protected implementation of Dispose pattern.
   Protected Overrides Sub Dispose(disposing As Boolean)
      If disposed Then Return
      
      If disposing Then
         handle.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

方法

Dispose()

執行與釋放 (Free)、釋放 (Release) 或重設 Unmanaged 資源相關聯之應用程式定義的工作。Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

適用於

另請參閱