デストラクタ
不要になったオブジェクトと自動メモリ管理
.NET Framework によって実行されるマネージコードは、メモリの管理を共通言語ランタイムに委ねています。共通言語ランタイムはインスタンスを監視し、不要になった時点で自動的にメモリから解放します。インスタンスは new 演算子によるオブジェクト生成式で作成しますが、作成したインスタンスをプログラムから明示的に削除することはできません。
共通言語ランタイムがインスタンスをメモリから消滅させるとき、自動的にデストラクタ(destructor)が呼び出されます。インスタンスが削除されるとき、何らかの処理を実行する必要がある場合、対象のクラス内でデストラクタ宣言(destructor-declaration)を記述してください。
~ デストラクタ名() { デストラクタ本体 }
デストラクタはチルダ記号 ~ から始まり、デストラクタ名にはデストラクタを宣言するクラスと同じ名前を指定します。つまり、コンストラクタ名と同じになります。デストラクタはパラメータを受け取ることはできず、戻り値も返せません。デストラクタ本体は、メソッドやコンストラクタと同様に任意の文を記述できるブロック文です。
デストラクタを呼び出すのは共通言語ランタイムであり、インスタンスが破棄されるタイミングはコードからは制御できません。共通言語ランタイムはオブジェクトを代入した変数がスコープから外れ、生成したインスタンスがコードから利用されなくなった時点で消滅資格(eligible for destruction)を与えます。消滅資格が設定された後、インスタンスのデストラクタはいつでも呼び出される可能性があります。
class MagicalGirl { ~MagicalGirl() { System.Console.WriteLine("逝ってしまったわ、円環の理に導かれて…"); } } class Test { public static void Main(string[] args) { MagicalGirl sayaka = new MagicalGirl(); } }
共通言語ランタイムはデストラクタを持つインスタンスを破棄するとき、自動的にデストラクタを呼び出します。コード1はデストラクタ宣言を持つ MagicalGirl を用意し、Main() メソッドで 1 つのインスタンスを生成しているだけです。おそらく、プログラムが終了するとき共通言語ランタイムによって不要なオブジェクトが検出され、生成したインスタンスのデストラクタが呼び出されるはずです。
もし、デストラクタが呼び出されない場合、以下のように Main() メソッド内のコードを書き換えてください。
new MagicalGirl(); System.GC.Collect(); System.GC.WaitForPendingFinalizers();
共通言語ランタイムの自動メモリ管理については割愛しますが、上記のコードで強制的に消滅資格のあるインスタンスの検出と破棄を実行しています。
デストラクタを持つことで、自分自身がメモリから消滅するタイミングを感知できます。ただし、多くの設計でデストラクタは不要であり、よほど必要に迫られない限りデストラクタを作成する必要はありません。オブジェクトが自動メモリ管理で追跡されない外部のリソース(ファイルやネットワークなど)と紐づいている場合、これを解除するにはデストラクタではなく Dispose というパターンが使われます。Dispose パターンの詳細は後述します。