IDisposable.Disposeメソッドによってリソースが破棄された場合、以降は破棄されたリソースにアクセスできないようにする必要があります。 このような場合にスローする例外がObjectDisposedExceptionです。 メソッド呼び出しやメンバ参照によって解放済みのリソースへのアクセスが生じる場合にこの例外をスローします。
ObjectDisposedExceptionコンストラクタの引数objectNameには例外をスローしたオブジェクトの名前を指定します。 通常はオブジェクトの名前として型の名前、具体的にはGetType().FullName
を指定します。
以下の例は、解放済みのリソースにアクセスしようとした場合にObjectDisposedExceptionをスローするようにしたものです。
すでに解放済みのリソースへのアクセスを試行した場合にObjectDisposedExceptionをスローする
Imports System
Imports System.Runtime.InteropServices
Class UnmanagedMemory
Implements IDisposable
Private ptr As IntPtr ' アンマネージメモリ領域を参照するポインタ
Public Sub New(ByVal size As Integer)
ptr = Marshal.AllocHGlobal(size)
End Sub
Public Sub Clear()
' Ptrが0の場合(すでにDisposeメソッドで解放済みの場合)、例外ObjectDisposedExceptionをスローする
' (例外の原因となるオブジェクト名として型名を指定する)
If ptr = IntPtr.Zero Then Throw New ObjectDisposedException(Me.GetType().FullName)
' そうでない場合はメソッドの通常の処理を行う
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
' すでに解放されている場合は何もしない(DisposeメソッドはObjectDisposedExceptionをスローしてはならない)
If ptr = IntPtr.Zero Then Return
Marshal.FreeHGlobal(ptr)
' 解放済みであることを示すためにIntPtr.Zeroを設定する
ptr = IntPtr.Zero
End Sub
End Class
Class Sample
Shared Sub Main()
' IDisposableインターフェイスを実装するオブジェクトを作成する
' (本来ならUsingステートメントを使ったほうがよいが、例示のため省略)
Dim mem As New UnmanagedMemory(4)
' Disposeメソッドを呼び出し、アンマネージリソースを解放する
mem.Dispose()
' アンマネージリソースへのアクセスを試みる
' (オブジェクトはすでに破棄されているため、ObjectDisposedExceptionとなる)
mem.Clear()
End Sub
End Class
実行結果
ハンドルされていない例外: System.ObjectDisposedException: 破棄されたオブジェクトにアクセスできません。 オブジェクト名 'UnmanagedMemory' です。
上記の例にもあるように、IDisposable.Disposeメソッドでは、すでに解放済みの場合であってもObjectDisposedExceptionをスローしないようにします。 ObjectDisposedExceptionは、使用しようとしたリソースが既に解放済みだった場合にスローします。
仮にDisposeメソッドでオブジェクトが破棄されている場合でも、解放済みリソースへのアクセスが生じない処理の場合はObjectDisposedExceptionをスローしないようにすることもできます。 例えば、IsDisposed
やIsClosed
のようなプロパティを用意する場合は、破棄されていてもObjectDisposedExceptionをスローしない動作とします。