System.IDisposable インターフェイス
この記事では、この API のリファレンス ドキュメントへの補足的な解説を提供します。
インターフェイスの IDisposable 主な用途は、アンマネージ リソースを解放することです。 ガベージ コレクターは、そのオブジェクトが使用されなくなったときに、マネージド オブジェクトに割り当てられたメモリを自動的に解放します。 ただし、ガベージ コレクションがいつ発生するかを予測することはできません。 さらに、ガベージ コレクターには、ウィンドウ ハンドルや開いているファイルやストリームなどのアンマネージ リソースに関する知識がありません。
このインターフェイスのメソッドを Dispose 使用して、ガベージ コレクターと組み合わせてアンマネージ リソースを明示的に解放します。 オブジェクトのコンシューマーは、オブジェクトが不要になったときにこのメソッドを呼び出すことができます。
警告
既存のクラスにIDisposableインターフェイスを追加することは互換性に影響する重大な変更です。 型の既存のコンシューマーはDisposeを呼び出すことができないため、型によって保持されているアンマネージリソースが解放されることは確実ではありません。
インスタンスが所有されているリソースが不要になったときに、型のコンシューマーによってIDisposable.Dispose 実装が呼び出されるため、マネージオブジェクトをSafeHandle でラップするか(推奨される方法)、コンシューマーがDisposeを呼び出し忘れた場合にアンマネージリソースを解放するために、Object.Finalizeをオーバーライドする必要があります。
重要
.NET Framework では、C++ コンパイラはリソースの確定的な破棄をサポートしており、メソッドを Dispose 直接実装することはできません。
このインターフェイスとメソッドの使用方法の詳細については、ガベージ コレクションと Object.FinalizeDispose メソッドの実装に関するトピックを参照してください。
IDisposable を実装するオブジェクトを使用する
アプリケーションでIDisposableインターフェイスを実装するオブジェクトのみを使用する場合は、オブジェクトの使用が終了したら、そのオブジェクトのIDisposable.Dispose実装を呼び出す必要があります。 プログラミング言語によっては、次の 2 つの方法のいずれかでこれを行うことができます。
- C# および Visual Basic の
using
ステートメント、F# のステートメントまたはusing
関数などの言語コンストラクトをuse
使用する。 - IDisposable.Dispose実装の呼び出しを
try
/finally
ブロックでラップする。
Note
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
ステートメント (use
F# の式) は、実際には構文上便利です。 コンパイル時に、言語コンパイラはtry
/finally
ブロックの中間言語 (IL) を実装します。
using
ステートメントの詳細については、 Using ステートメント または using ステートメント のトピックを参照してください。
Try/Finally ブロック
プログラミング言語で、C# または Visual Basic のステートメントや F# のステートメントのようなusing
コンストラクトがサポートされていない場合、またはuse
使用しない場合は、ステートメントの/try
finally
ブロックから実装をfinally
呼び出IDisposable.Disposeすことができます。 次の例は、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
、「Try...」を参照してください。 キャッチ。。。Finally ステートメント、 try-finally、 try...finally Expression、または try-finally ステートメント。
IDisposable を実装する
型でアンマネージ リソースを直接使用する場合、または破棄可能なリソースを自分で使用する場合は、実装 IDisposable する必要があります。 インスタンスが不要になった場合は 、型のコンシューマーがIDisposable.Dispose実装を呼び出してリソースを解放できます。 Disposeの呼び出しに失敗したケースを処理するには、SafeHandleから派生したクラスを使用してアンマネージリソースをラップするか、参照型に対してObject.Finalizeメソッドをオーバーライドする必要があります。 どちらの場合も、アンマネージリソースの解放、解放、またはリセットなど、アンマネージリソースを使用した後に必要なクリーンアップを実行するには、Disposeメソッドを使用します。 実装IDisposable.Disposeの詳細については、Dispose(bool) メソッドのオーバーロードを参照してください。
重要
アンマネージリソースを使用し、破棄する必要があるサブクラスを持っているか、または存在する可能性が高い基底クラスを定義する場合は、次のセクションで説明する様に、IDisposable.Disposeメソッドを実装し、2 番目のDispose
オーバーロードを提供する必要があります。
IDisposable と継承階層
破棄可能である必要があるサブクラスを持つ基底クラスは、次のようにIDisposableを実装する必要があります。 このパターンは、(Visual Basic では)NotInheritable
実装されていないsealed
型に対して実装IDisposableするたびに使用する必要があります。
- 1 つのパブリックな非仮想メソッドと保護された仮想Dispose()
Dispose(Boolean disposing)
メソッドを提供する必要があります。 - メソッドは Dispose() 呼び出す
Dispose(true)
必要があり、パフォーマンスのために終了処理を抑制する必要があります。 - 基本型はファイナライザーを含めることはできません。
次のコード フラグメントは、基底クラスの dispose パターンを反映しています。 型が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)
メソッドをオーバーライドしているだけです。
次のコード フラグメントは、派生クラスの dispose パターンを反映しています。 型が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
.NET