2020年11月30日
川俣晶の縁側ソフトウェアC# コーディング How To total 1283 count

【入門級】オブジェクトが消滅するタイミングをイベントとして受け取りたい 【最終回】

Written By: 川俣 晶連絡先

 オブジェクトは生まれて消えます。

 生まれるタイミングはすぐ分かります。

 new演算子を書けばそこが産まれるタイミングだし、コンストラクタなら確実にそのタイミングで実行されるコードを書けます。

 では、消えるタイミングはどうでしょうか。

 ファイナライザーというものがあり、C#ではデストラクターと呼ばれる構文でそれを書くことができます。

 しかし、これの利用はお勧めではありません。

 いつ呼び出されるか分からないし、場合によっては呼び出されないからです。

 サンプルソースでは呼び出されていません。

 現実的には、IDisposableを実装してusing文と併用するのがお勧めです。こうすると、使い終わった時点でDisposeメソッドが呼ばれます。

罠の数々 §

  • デストラクターは確実に呼び出されない。しかし、using文を忘れたDisposeメソッドもはやり呼び出されない。C#とは確実を求めないことで性能向上や使い勝手の改善を行うプログラミング言語であることに留意しよう。

参考リンク §

ファイナライザー (C# プログラミング ガイド)

GC.Collect メソッド

IDisposable インターフェイス

 ファイナライザーとデストラクターの用語は混乱している。上記のファイナライザーのURLはdestructorsとなっている。上記のページはマイクロソフト公式だがファイナライザー(デストラクターとも呼ばれる)とまで話がまるまっていることを確認してみよう。

 また上記のリンクを辿って、GC.Collect メソッドを呼び出しても全てのオブジェクトが確実に回収されない理由を考えてみよう。

リポジトリ §

https://github.com/autumn009/cshowto

Fnalizer §

using System;

class Sample : IDisposable

{

    public Sample()

    {

        Console.WriteLine("私、産まれました!");

    }

    ~Sample()

    {

        Console.WriteLine("私、消えます!");

    }

    public void Dispose()

    {

        Console.WriteLine("私、Disposeされました!");

    }

}

class Program

{

    static void Main()

    {

        // ファイナライザー?

        var a = new Sample();

        Console.WriteLine($"a of {a} is here!");

        a = null;

        GC.Collect();

        // IDisposable インターフェース?

        using var b = new Sample();

        Console.WriteLine($"b of {b} is here!");

    }

}

実行結果

私、産まれました!

a of Sample is here!

私、産まれました!

b of Sample is here!

私、Disposeされました!

COOL C# CREW

C#ハウツー連載の解説増量、カラーのソース、新規書き下ろし追加の読みやすい単行本はこちら。

C#ハウツー: 逆引き入門・こんな機能はどう書くの?