実行時の型を確認する方法

プログラミングC# 第6版 4.12


実行時に型を取得する方法です。これは例えば色々なクラスを一旦object型の配列に格納した後に、そこから元の型に戻して処理を実行させる時などに使えます。

using System;

class CClassA {
    public void Foo () {
        Console.WriteLine("CClassA.Foo");
    }
}

class CClassB {
    public void Bar () {
        Console.WriteLine("CClassB.Bar");
    }
}

class Program {
    static void Main () {
        // まったく関連のないクラス同士を格納
        object[] list = {
            new CClassA(),
            new CClassB(),
        };
        
        foreach(object item in list) {
            // クラスの型によって処理分けする
            if ( item is CClassA ) {
                (item as CClassA).Foo();
            }
            else if ( item is CClassB ) {
                (item as CClassB).Bar();
            }
        }
    }
}
$ main
CClassA.Foo
CClassB.Bar

「変数 is クラス型名」で何のクラスかどうかを判別し、「変数 as クラス型名」で目的の型に変換することができます。

ちなみに目的の型に変換する方法としてはキャストもありますよね。

class Program {
    static void Main () {
        object[] list = {
            new CClassA(),
            new CClassB(),
        };
        
        foreach(object item in list) {
            // asを使わずにキャストを使ってみる
            if ( item is CClassA ) {
                ((CClassA)item).Foo();
            }
            else if ( item is CClassB ) {
                ((CClassB)item).Bar();
            }
        }
    }
}
$ main
CClassA.Foo
CClassB.Bar

キャストでもちゃんと動きますね。ではasとキャストの違いはいったいなんなのか?

それは元の型と、変換させようとしている型に何も関連性が無い場合に、asとキャストで挙動が変わります。

まずキャストだとどうなるか試してみます。

class Program {
    static void Main () {
        object tmp = new CClassA();
        
        // CClassAのオブジェクトなのにCClassBでキャストしてみる
        CClassB cobj = (CClassB)tmp;
    }
}

これをコンパイルして実行するとプログラムが落ちて、以下のエラーが表示されます。

$ main

ハンドルされていない例外: System.InvalidCastException: 型 'CClassA' のオブジェクトを型 'CClassB' にキャストできません。
   場所 Program.Main()

例外が発生しました。

では次にasを使った場合を試してみます。

class Program {
    static void Main () {
        object tmp = new CClassA();
        
        // CClassAのオブジェクトなのにasでCClassBへ変換してみる
        CClassB cobj = tmp as CClassB;
        if ( cobj == null ) {
            Console.WriteLine("変換できませんでした");
        }
    }
}
$ main
変換できませんでした

asを使った場合は例外は発生せずに、変わりに戻り値がnullになります。

nullになるだけなのでifで比較し、処理を適切に続けることが可能になります。

もちろんキャストの場合でも無理やりtryで例外をキャッチして処理の続行をすることもできますが、些か冗長すぎますよね。

ちなみに本によると、この手の処理の場合にisはあまり使用せずにいきなりasを使って型変換し、nullで比較する方が効率的だと書いてありました。

ということで本ブログでもisは使わずにasを使うようにしたいと思います。