読者です 読者をやめる 読者になる 読者になる

謎言語使いの徒然

適当に気になった技術や言語を流すブログ。

.NET を理解する6

.NET C# Tips
標準インターフェースを覚えてみる

標準インターフェースとその役割について考えてみる。

  • IComparable : Generic あり。オブジェクトの大小比較を行う。ソート時の評価で利用。
  • IDisposeable : オブジェクトガベージ時にリソースを開放する。com オブジェクトや、Win32API をコールする際に利用する。開放するべきオブジェクトがあると明示するためのものと思ってもよいかも?通常インターフェースなのでシステムで自動に呼ぶことも無い。
  • IConvertible : オブジェクトを共通言語ランタイム型に変換するメソッドを定義する。Convertクラスでの変換に使います。
  • ICloneable : オブジェクトのコピーを作成する為の Clone メソッドインターフェース。
  • IFormattable : 書式(IFormatProvider)付きの ToString メソッドを定義します。
  • IEqutable : 2 つのインスタンスが等しいかどうかを判断するための Equals メソッドを定義してます・
  • IEqualityComparer : IEqutable の Equals のほかに、GetHashCode メソッドも定義します。辞書用ですね。

相変わらず論よりRunで。
使い方や用途の分かりやすい IComparable, ICloneable, IFormattable, IEqutable, IEqualityComparer は省略。分かりづらいのだけ実装サンプルを、、、。

IDisposeable の実装

FxCOP なるライブラリ向け実装規約準拠の確認ツールがある。そのツールを使ったときに、正しく実装されて無いと、警告が出ます。

public class DisposeableSample : IDisposable
{
    private bool disposed;

    // デストラクタです。
    ~DisposeableSample()
    {
        Console.WriteLine("~DisposeableSample");
        this.Dispose(false);
    }

    // IDisposable.Dispose() の実装です。
    public void Dispose()
    {
        Console.WriteLine("Dispose");

        // リソースの開放を実装するメソッドをコールします。
        this.Dispose(true);

        // ガベージコレクタに、終了処理をコールするよう通知します。
        System.GC.SuppressFinalize(this);
    }

    // 実際にリソースを開放する処理を行います。
    private void Dispose(bool disposing)
    {
        Console.WriteLine("Dispose({0})", disposing);

        if (!this.disposed)
        {
            if (disposing)
            {
                // マネージデータの開放はここです。
                // (.NET 系ライブラリの開放)
            }

            // .NET 系意外のリソースの開放はここです。

            // dispose 済みフラグを立てます。
            this.disposed = true;
        }
    }
}

で、この実装は IDisposeable を継承する = 開放しなければならないリソースがあるということになる。System.IO.FileStream がいい例かもしれませんね。
通常使う場合は、FileStream.Close メソッド同様に

using (DisposeableSample use = new DisposeableSample())
{
    Console.WriteLine("使いませんけど");
}

// もしくは
DisposeableSample use2;
try
{
    use2 = new DisposeableSample();
}
catch(Exception e){}
finally
{
    use2.Dispose();
}


/* 実行結果
~DisposeableSample
Dispose(True)
*/

を書くほうがよい。
尚、いつリソース開放されるかをガベコレに任せてよいのであれば、開放処理を書かなくてもデストラクタ経由でマネージリソース意外は開放されます。*1

DisposeableSample sample = new DisposeableSample();
sample = null;

// ガベコレ強制執行。
System.GC.Collect();

/* 実行結果
~DisposeableSample
Dispose(False)
*/
IConvertible の実装

見ての通り、Convert クラス用インターフェース。
試しに「キャストにならないかなー」とか試したら InvalidCastException 食らった(−−;
通常、CTS の基本値型や string に変換することは無いから、別にいっかなーという気がしないではない。

class Program
{
    static void Main(string[] args)
    {
        IntegerString data = new IntegerString();
        data.Value = "2048";
        string data2 = "4096";

        int intVal = Convert.ToInt32(data);
        int intVal2 = Convert.ToInt32(data2);

        // InvalidCastException
        double fValue = Convert.ToDouble(data);
    }
}

public class IntegerString : IConvertible
{
    public string Value
    {
        get;
        set;
    }

    public TypeCode GetTypeCode()
    {
        return TypeCode.Object;
    }

    public object ToType(Type conversionType, IFormatProvider provider)
    {
        if (conversionType == typeof(int))
        {
            return Convert.ToInt32(this.Value, provider);
        }

        throw new InvalidCastException();
    }

    public int ToInt32(IFormatProvider provider)
    {
        return Convert.ToInt32(this.Value, provider);
    }

    public double ToDouble(IFormatProvider provider)
    {
        throw new InvalidCastException();
    }

    /* 以下省略 */

}

*1:まぁマネージリソースも参照が消えるので、ガベコレ対象となり、そのうち消えるでしょうけど