【C#】Interfaceを継承しているかを判断しついでにコンバートしてみる

みなさんこんにちは!ひろぽんです。

今回はInterfaceを継承しているかの判断をしたうえで、ついでにコンバートしてみるという題で書いていきたいと思います。

では早速!

目次

まずはこんなクラスを用意する!

💡 is / as / 暗黙キャストの使い分けは別記事 C# Interface の継承判定と暗黙キャストの定石 で詳しくまとめてます。

Interfaceの準備

まずはInterfaceを二つ用意します!

    public interface IVehicle
    {
        string MoveSound { get; }
    }
    public interface ICar
    {
        string Maker { get; }
    }

でこれらを継承したクラスを用意します!

    public class Subaru : IVehicle , ICar
    {
        public string MoveSound => "ブーブー";
        public string Maker => "Subaru";
    }
    public class Plane : IVehicle
    {
        public string MoveSound => "ごぉーーーーーー";
    }

SubaruクラスはIVehicle InterfaceとICar Interfaceを継承しています

が、PlaneクラスはIVehicle Interfaceしか継承していません!

Interfaceを継承しているかの判断

で、下記のようなコードを書いて、クラスがIntefaceを継承しているかを見てみましょう!

まずは下記のコードで継承しているかの判断ができます。

        static void Main(string[] args)
        {
            var plane = new Plane();
            var car = plane as ICar;

        if (car != null)
        {
            Console.WriteLine(car.Maker);
        }
        else
        {
            Console.WriteLine("PlaneはICarを継承していません。");
        }

        Console.ReadLine();
    }</code></pre></div>

継承していればNullにならずに変数にコンバートしたものがはいります。

が、継承していなければNullが入ります。

InterfaceからInterfaceの継承チェックもできる。

上記はクラスがInterfaceを継承しているかを見ましたが、Intefaceの型で別のInterfaceチェックもできます。

        static void Main(string[] args)
        {
            IVehicle plane = new Plane();
            var car = plane as ICar;

        if (car != null)
        {
            Console.WriteLine(car.Maker);
        }
        else
        {
            Console.WriteLine(&quot;PlaneはICarを継承していません。&quot;);
        }

        Console.ReadLine();
    }
}</code></pre></div>

こんな感じでvarからIVehicleにしてもチェックできますし、下記の感じでもできます。

        static void Main(string[] args)
        {
            IVehicle subaru = new Subaru();
            var car = subaru as ICar;

        if (car != null)
        {
            Console.WriteLine(car.Maker);
        }
        else
        {
            Console.WriteLine(&quot;PlaneはICarを継承していません。&quot;);
        }

        Console.ReadLine();
    }</code></pre></div>

Interfaceを継承していたらコンバートする

とはいえ、一度変換した後にNullチェックをするのはめんどくさい!ということで、if分の中で同時に変換できます!

        static void Main(string[] args)
        {
            IVehicle subaru = new Subaru();

        if (subaru is ICar car)
        {
            Console.WriteLine(car.Maker);
            return;
        }
        Console.WriteLine(&quot;PlaneはICarを継承していません。&quot;);
        Console.ReadLine();

    }</code></pre></div>

Planeクラスでやるとこんな感じになります。

        static void Main(string[] args)
        {
            IVehicle plane = new Plane();

        if (plane is ICar car)
        {
            Console.WriteLine(car.Maker);
            Console.ReadLine();
            return;
        }
        Console.WriteLine(&quot;PlaneはICarを継承していません。&quot;);
        Console.ReadLine();

    }</code></pre></div>

Githubで今回のコードを公開しています!

下記リポジトリのInterfaceConvertで今回のソースを公開しています!

GitHub
GitHub - HayashiyamaHiroshi/blog-source-demo Contribute to HayashiyamaHiroshi/blog-source-demo development by creating an account on GitHub.

💡 補足: 業務系の現場でよくハマるパターン

俺もこの Interface 継承判定、 業務でハマってきたところを3つ並べておきます。

① is と typeof() の混同

obj is IFoo は継承チェーン全部見るが、 obj.GetType() == typeof(IFoo) は厳密に一致のみ (継承先は false)。 ポリモーフィズム判定なら必ず is。 typeof 使う場面は具象クラス比較のみ。

② as 演算子の null 判定漏れ

var foo = obj as IFoo 後の null チェック忘れ → NRE。 C# 7+ なら if (obj is IFoo foo) のパターンマッチで null 判定込み・1行で済む。

③ ジェネリック制約での Interface 判定

where T : IFoo でジェネリック制約掛けると compile-time に判定。 runtime の is より型安全。 既存コード内で is を多用してる箇所はジェネリック化で改善できる場合多い。

❓ よくある質問

Q1. is と typeof() どっちが速い?

A. is の方が速い (JIT 最適化済)。 typeof().IsAssignableFrom() は reflection 経由で重い。 hot path では is 一択。

Q2. Interface の継承確認をジェネリックで書く方法は?

A. typeof(IFoo).IsAssignableFrom(typeof(T))。 ただし runtime チェックなので、 可能なら where T : IFoo の制約で compile-time に。

Q3. 複数 Interface を同時判定するには?

A. obj is IFoo && obj is IBar で AND。 OR なら obj is IFoo || obj is IBar。 C# 9+ の and/or パターンマッチも使える。

Q4. Generic 制約と is の使い分けは?

A. 静的に判定できる場面 (型が分かってる) は Generic 制約動的な型 (Object 引数等) は is。 制約使えるところは制約優先 (型安全 + 性能)。

Q5. Interface のキャストに失敗した時の処理は?

A. (IFoo)obj 直接キャストは InvalidCastException。 安全に処理するなら obj as IFoo で null 返却 or is パターンマッチで分岐。 詳細は 継承判定と暗黙キャストの定石 参照。

📚 関連記事

この記事が気に入ったら
いいねしてね!

どんどんシェア待ってるぜ!!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次