.NET 2.0 に向けて、IDisposable.Dispose() を見直そう

.NET 2.0 (beta) において、IDisposable.Dispose() はアンマネージドリソースとは直接的にも間接的にも無縁な使い方のほうが多くなってきている。
これは特に問題ではなく、以前から

アンマネージドリソースを開放することではなく、オブジェクトの状態を開放可能状態*1に変化させることであり、アンマネージドリソソースの開放は、開放可能状態へ変化するための典型的な実装例でしかなく、状態変化の結果でしかない。(つまり、IDisposable.Dispose() メソッドの目的ではない)

ということは何度も言ってきたし、実際に .NET Framework 1.1 の標準ライブラリの大半はそのように実装されている。アンマネージドリソースが前面に出てきてしまう理由は、MSDN でも

Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.

と記載されていることや、「ガーベッジコレクタによる遅いオブジェクトの開放とファイナライザによるリソース開放がもたらす問題」について、IDisposable.Dispose() による解決を解説する記事でも、アンマネージドリソースを例にするほうが説明が現実的になってしまうなど、要因は多い。
冒頭にも書いたように、.NET 2.0 になって、IDisposable を取り巻く環境に変化があらわれている。VisualBasic に Using ステートメントが追加されたり、イテレータの実装オブジェクトに IDisposable を利用した状態処理が自動的に実装されたり、C++ へのファイナライザ構文の追加と共にデストラクタコードが IDisposable.Dispose() メソッドとして実装されるなど、アンマネージドリソースと無縁な場所で、多くの記事などで解説される「本質的な IDisposable の目的」としての利用がどんどんと増える傾向になっている。
.NET 2.0 では IDisposable インターフェスは、「アンマネージドリソースを開放するための実装を提供する共通のインターフェス」ではなく、「マネージドオブジェクトとして開放可能になるための実装を提供する共通のインターフェス」なのである。じゃあ、アンマネージドリソースは特別にマーキングされないの?ってことになるのだが、個人的にはアンマネージドリソースに対して特別なマーキングなど必要なく、アンマネージドリソースを利用しているかどうかに対して開発者*2が意識する必要がないことがベターだと思っているので、そんなもの必要ないと思う。まあ、いまさら

  public interface IDisposableEx : IDisposable
  {
    void Dispose(bool inManaged);
  }

  public class HasUnmanagedResource : IDisposableEx
  {
    ~HasUnmanagedResource()
    {
      (this as IDisposableEx).Dispose(false);
    }

    IDisposable.Dispose()
    {
      (this as IDisposableEx).Dispose(true);
      GC.SupressFinalize(this);
    }

    IDisposableEx.Dispose(bool inManaged)
    {
      if (inManaged)
      {
        /* ... dispose managed resource(s) */
      }

      /* ... dispose unmanaged resource(s) */
    }
  }

なんてインターフェスの追加や、ISerializable を実装するクラスのコンストラクタのようなファイナライザに関する特殊対応はできないだろうけど、Windows の世界において .NET が OS コアになる頃*3には自然とこういう形になっているのかもね?

*1:ガーベッジコレクタによる任意タイミングによる開放が可能な状態

*2:クラスライブラリの利用者

*3:Longhorn の次の次の Windows ぐらい?