CS.IDISP.DTOR
IDisposable を実装するときに、デストラクター (ファイナライザー) を提供します。
この規則は、Idisposable インターフェイスを実装しているクラスで、ファイナライザー (デストラクター) を実装していないコードを識別します。一部のクラスでは、クラスによって割り当てられたリソースをユーザーが解放できるように、Idisposable インターフェイスを実装しています。ただし、ユーザーは Dispose メソッドを呼び出すことを忘れる可能性があります。防御的にコーディングするには、そのようなクラスがファイナライザー (C# 内のデストラクター、管理された C++) も確実に実装するようにしてください。これにより、ユーザーが Dispose メソッドを呼び出すことを忘れても、ガベージコレクターがファイナライザーを呼び出すときに、リソースは解放されます。
脆弱性とリスク
標準の設計パターンを実装しなければ、メモリの管理ミスのリスクが高まります。
軽減と防止
問題は、Idisposable インターフェイスを実装し、デストラクターから Dispose() を呼び出すことで修正されます。
脆弱コード例
コピー
using System;
public class A : Idisposable
{
private bool _alreadyDisposed = false;
public A()
{
// resource allocated here
}
public virtual void Dispose()
{
Dispose(true);
}
public virtual void Dispose(bool isDisposing)
{
if (_alreadyDisposed)
{
return;
}
if (isDisposing)
{
// Free managed resources
}
// Free unmanaged resources
_alreadyDisposed = true;
}
// VIOLATION: Does not implement the destructor.
// However, Idisposable interface is implemented.
}
修正コード例
コピー
// Problem is fixed by implementing Idisposable interface
// and calling Dispose() from the destructor.
Using System;
public class A : Idisposable
{
private bool _alreadyDisposed = false;
public A()
{
// resource allocated here
}
// FIXED: Destructor implemented.
// Also note the call to GC.SuppressFinalize().
~A()
{
// Dispose() called from the destructor
Dispose(false);
}
public virtual void Dispose()
{
Dispose(true);
GC.SuppressFinalize();
}
public virtual void Dispose(bool isDisposing)
{
if (_alreadyDisposed)
{
return;
}
if (isDisposing)
{
// Free managed resources
}
// Free unmanaged resources
_alreadyDisposed = true;
}
}
リファレンス: .NET Framework General Reference、Class Library デベロッパー向けの設計ガイドライン。