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