以下は、disposeパターンにしたがって、IDisposableインターフェイスとファイナライザを実装するクラスResourceBase
と、それを継承したクラスExtendedResource
を作成する例です。
disposeパターンに従ったクラスの実装と継承の例
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
' 使用後に解放されるべきリソースを扱うクラス
Class ResourceBase
Implements IDisposable
Private disposed As Boolean = False ' リソースが破棄(解放)されていることを表すフラグ
Private ptr As IntPtr = Marshal.AllocHGlobal(4) ' コンストラクタ等で確保されるアンマネージリソースを想定したオブジェクト
' ファイナライザ
Protected Overrides Sub Finalize()
' アンマネージリソースのみを破棄させる
Dispose(false)
End Sub
' IDisposable.Disposeの実装
Public Overloads Sub Dispose() Implements IDisposable.Dispose
' アンマネージリソースと、マネージリソースの両方を破棄させる
Dispose(true)
' すべてのリソースが破棄されているため、以後ファイナライザの実行は不要であることをガベージコレクタに通知する
GC.SuppressFinalize(Me)
End Sub
' リソースの解放処理を行うためのメソッド
Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
' 既にリソースが破棄されている場合は何もしない
If disposed Then Return
' アンマネージリソースと、マネージリソースの両方の破棄が要求された場合
If disposing Then
' このクラスはマネージリソースを持たないので、ここですべきことは無い
End If
' 破棄されていないアンマネージリソースの解放処理を行う
If ptr <> IntPtr.Zero Then
Marshal.FreeHGlobal(ptr)
ptr = IntPtr.Zero
End If
' リソースは破棄されている
disposed = True
End Sub
' 既にリソースが破棄されているかチェックして、ObjectDisposedExceptionをスローするためのメソッド
Protected Sub ThrowIfDisposed()
If disposed Then Throw New ObjectDisposedException(Me.GetType().FullName)
End Sub
' 保持しているリソースを使って何らかの操作を行うメソッドを想定
Public Overridable Sub UseResource()
' 既にリソースが破棄されているかチェックし、破棄されていればObjectDisposedExceptionをスローする
ThrowIfDisposed()
' 以降、リソースが利用可能な場合はそれを使った操作を行う
End Sub
End Class
' IDisposableとファイナライザが実装された型を継承したクラス
Class ExtendedResource
Inherits ResourceBase
Private ptr As IntPtr = Marshal.AllocHGlobal(8) ' コンストラクタ等で確保されるアンマネージリソースを想定したオブジェクト
Private stream As Stream = Stream.Null ' コンストラクタ等で確保されるマネージリソースを想定したオブジェクト
' 基底クラスのリソース解放処理をオーバーライド
' (ファイナライザ・IDisposable.Disposeメソッドは直接オーバーライドせず、このメソッドで実装する)
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
Try
' アンマネージリソースと、マネージリソースの両方の破棄が要求された場合
If disposing Then
' 破棄されていないマネージリソースの解放処理を行う
If Not stream Is Nothing Then
stream.Close() ' Disposeメソッド、あるいはそれを呼び出すメソッドを呼び出して解放する
stream = Nothing
End If
End If
' 破棄されていないアンマネージリソースの解放処理を行う
If ptr <> IntPtr.Zero Then
Marshal.FreeHGlobal(ptr)
ptr = IntPtr.Zero
End If
Finally
' 例外が発生しても基底クラスのDisposeメソッドを確実に呼び出すようにする
MyBase.Dispose(disposing)
End Try
End Sub
Public Overrides Sub UseResource()
' 既にリソースが破棄されているかチェックし、破棄されていればObjectDisposedExceptionをスローする
ThrowIfDisposed()
' 以降、リソースが利用可能な場合はそれを使った操作を行う
End Sub
End Class
ここでは例示のためハンドル・ポインタをそのまま扱っていますが、可能ならSafeHandleでラップするようにします。 このほか、個々の事項については以下を参照してください。