動くコード図鑑技術記事現場の渡り方キャリア論すべての記事About
技術記事

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

バイブス父さん
現役の業務SE
2020年11月3日7 min read
【C#】Interfaceを継承しているかを判断しついでにコンバートしてみる

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

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

では早速!

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

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

Interfaceの準備

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

Interfaceの準備 (csharp)#ef6f895a3a12
    public interface IVehicle
    {
        string MoveSound { get; }
    }
▸ この snippet は実行結果未収録
▸ 実行結果は未収録です
Interfaceの準備 (csharp)#34bea12e472d
    public interface ICar
    {
        string Maker { get; }
    }
▸ この snippet は実行結果未収録
▸ 実行結果は未収録です

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

Interfaceの準備 (csharp)#bb06c59edfc9
    public class Subaru : IVehicle , ICar
    {
        public string MoveSound => "ブーブー";
        public string Maker => "Subaru";
    }
▸ この snippet は実行結果未収録
▸ 実行結果は未収録です
Interfaceの準備 (csharp)#4daba4d61b7d
    public class Plane : IVehicle
    {
        public string MoveSound => "ごぉーーーーーー";
    }
▸ この snippet は実行結果未収録
▸ 実行結果は未収録です

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

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

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

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

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

Interfaceを継承しているかの判断 (csharp)#410a80545d69
        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();
    }
▸ 実行ボタンで結果を表示

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

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

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

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

InterfaceからInterfaceの継承チェックもできる。 (csharp)#798be77e4d3a
        static void Main(string[] args)
        {
            IVehicle plane = new Plane();
            var car = plane as ICar;
 
        if (car != null)
        {
            Console.WriteLine(car.Maker);
        }
        else
        {
            Console.WriteLine("PlaneはICarを継承していません。");
        }
 
        Console.ReadLine();
    }
}
▸ 実行ボタンで結果を表示

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

InterfaceからInterfaceの継承チェックもできる。 (csharp)#d2480278713e
        static void Main(string[] args)
        {
            IVehicle subaru = new Subaru();
            var car = subaru as ICar;
 
        if (car != null)
        {
            Console.WriteLine(car.Maker);
        }
        else
        {
            Console.WriteLine("PlaneはICarを継承していません。");
        }
 
        Console.ReadLine();
    }
▸ 実行ボタンで結果を表示

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

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

Interfaceを継承していたらコンバートする (csharp)#2ec7ce5942d1
        static void Main(string[] args)
        {
            IVehicle subaru = new Subaru();
 
        if (subaru is ICar car)
        {
            Console.WriteLine(car.Maker);
            return;
        }
        Console.WriteLine("PlaneはICarを継承していません。");
        Console.ReadLine();
 
    }
▸ 実行ボタンで結果を表示

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

Interfaceを継承していたらコンバートする (csharp)#1e6b84fd6356
        static void Main(string[] args)
        {
            IVehicle plane = new Plane();
 
        if (plane is ICar car)
        {
            Console.WriteLine(car.Maker);
            Console.ReadLine();
            return;
        }
        Console.WriteLine("PlaneはICarを継承していません。");
        Console.ReadLine();
 
    }
▸ 実行ボタンで結果を表示

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

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

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

俺もこの 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 パターンマッチで分岐。 詳細は 継承判定と暗黙キャストの定石 参照。

📚 関連記事

執筆者

バイブス父さん — 業務 SE 7 年 (正社員 2 / フリーランス 5)。 現職は SEO 直轄部の AI アドバイザー兼 PL、 副業で中小 SIer の CTO。 SES 複数社・フリーランスエージェント複数経由の経験ベースで「業務 SE 視点」 の技術 + キャリア記事を書いています。

🐦 X: @hiro_progra0524 (日々の現場メモ更新中)
📝 About Me で経歴詳細を見る

この記事のコードと手順は ぜんぶ動作検証済み。 安心して現場で試してくれ。
バイブス父さん

現役の業務SE。C# / SQL Server 保守の現場から、コードも人もキャリアも全部書く。 実体験ベース。

運営者について