IDisposable インターフェイス

定義

アンマネージ リソースを解放するためのメカニズムを提供します。

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
派生
属性

次の例は、インターフェイスを実装するリソースクラスを作成する方法を示して IDisposable います。

#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(disposing: true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SuppressFinalize 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(disposing: false) is optimal in terms of
            // readability and maintainability.
            Dispose(disposing: 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(disposing:=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(disposing:=False) is optimal in terms of
         ' readability and maintainability.
         Dispose(disposing:=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

注釈

このインターフェイスの主な用途は、アンマネージリソースを解放することです。 ガベージコレクターは、そのオブジェクトが使用されなくなったときに、マネージオブジェクトに割り当てられたメモリを自動的に解放します。 ただし、ガベージコレクションがいつ発生するかを予測することはできません。 さらに、ガベージコレクターは、ウィンドウハンドルや開いているファイルやストリームなどのアンマネージリソースに関する情報を持っていません。

このインターフェイスのメソッドを使用して、 Dispose ガベージコレクターと共にアンマネージリソースを明示的に解放します。 オブジェクトのコンシューマーは、オブジェクトが不要になったときにこのメソッドを呼び出すことができます。

警告

既存のクラスにIDisposableインターフェイスを追加することは互換性に影響する重大な変更です。 型の既存のコンシューマーはDisposeを呼び出すことができないため、型によって保持されているアンマネージリソースが解放されることは確実ではありません。

インスタンスが所有されているリソースが不要になったときに、型のコンシューマーによってIDisposable.Dispose 実装が呼び出されるため、マネージオブジェクトをSafeHandle でラップするか(推奨される方法)、コンシューマーがDisposeを呼び出し忘れた場合にアンマネージリソースを解放するために、Object.Finalizeをオーバーライドする必要があります。

重要

.NET Framework では、C++ コンパイラはリソースの決定的な破棄をサポートしており、 Disposeメソッドを直接実装することはできません。

このインターフェイスとメソッドの使用方法の詳細については、 Object.FinalizeガベージコレクションDispose メソッドの実装 」のトピックを参照してください。

IDisposable を実装するオブジェクトの使用

アプリケーションでIDisposableインターフェイスを実装するオブジェクトのみを使用する場合は、オブジェクトの使用が終了したら、そのオブジェクトのIDisposable.Dispose実装を呼び出す必要があります。 プログラミング言語によっては、次の 2 つの方法のいずれかでこれを行うことができます。

  • C# および Visual Basic の using ステートメントなどの言語構造を使用する。

  • IDisposable.Dispose実装の呼び出しをtry/finallyブロックでラップする。

注意

IDisposableを実装する型のドキュメントでは、その事実やDispose実装を呼び出すためのリマインダーが含まれています。

C# および Visual Basic using ステートメント

言語がusing(C#) ステートメント、 Using(Visual Basic) ステートメントなどをサポートしている場合、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; } }
}
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 実際には構文的に便利です。 コンパイル時に、言語コンパイラはtry/finallyブロックの中間言語 (IL) を実装します。

usingステートメントの詳細については、 Using ステートメント または using ステートメント のトピックを参照してください。

Try/Finally ブロック

使用するプログラミング言語がのようなコンストラクトをサポートしないかどうか、 using C# または Visual Basic では、ステートメントでそれを使用していない場合を呼び出すことができます、IDisposable.Disposeから実装、finallyのブロックをtry/finallyステートメント。 次の例は、usingブロックの前の例では、 try/finallyブロックします。

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...Catch...Finally ステートメントtry-finally、またはtry-finally ステートメントを参照してください。

IDisposable の実装

IDisposable型でアンマネージリソースを直接使用する場合、または自分で破棄可能なリソースを使用する場合は、を実装する必要があります。 インスタンスが不要になった場合は 、型のコンシューマーがIDisposable.Dispose実装を呼び出してリソースを解放できます。 Disposeの呼び出しに失敗したケースを処理するには、SafeHandleから派生したクラスを使用してアンマネージリソースをラップするか、参照型に対してObject.Finalizeメソッドをオーバーライドする必要があります。 どちらの場合も、アンマネージリソースの解放、解放、またはリセットなど、アンマネージリソースを使用した後に必要なクリーンアップを実行するには、Disposeメソッドを使用します。 の実装の詳細につい IDisposable.Dispose ては、「 Dispose (bool) メソッドのオーバーロード」を参照してください。

重要

アンマネージリソースを使用し、破棄する必要があるサブクラスを持っているか、または存在する可能性が高い基底クラスを定義する場合は、次のセクションで説明する様に、IDisposable.Disposeメソッドを実装し、2 番目のDisposeオーバーロードを提供する必要があります。

IDisposable および継承階層

破棄可能である必要があるサブクラスを持つ基底クラスは、次のようにIDisposableを実装する必要があります。 IDisposable sealed (Visual Basic) ではない任意の型にを実装する場合は常に、このパターンを使用する必要があり NotInheritable ます。

  • 1つのパブリック、非仮想メソッド、 Dispose() および保護された仮想メソッドを提供する必要があり Dispose(Boolean disposing) ます。

  • Dispose()メソッドはを呼び出す必要があり、 Dispose(true) パフォーマンスのために終了処理を抑制する必要があります。

  • 基本型はファイナライザーを含めることはできません。

次のコード片は、基底クラスの dispose パターンを反映しています。 型がObject.Finalizeメソッドをオーバーライドしないことを前提としています。

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(disposing: 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(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
         handle.Dispose()
         ' Free any other managed objects here.
         '
      End If

      disposed = True
   End Sub
End Class

メソッドをオーバーライドする場合 Object.Finalize 、クラスは次のパターンを実装する必要があります。

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(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;
   }

   ~BaseClass()
   {
      Dispose(disposing: 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)メソッドをオーバーライドしているだけです。

次のコード片は、派生クラスの dispose パターンを反映しています。 型がObject.Finalizeメソッドをオーバーライドしないことを前提としています。

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()

アンマネージ リソースの解放またはリセットに関連付けられているアプリケーション定義のタスクを実行します。

適用対象

こちらもご覧ください