restofwaterimpのぎじゅつMemo

SIerに所属。企画から運用まで幅広くやってます。C#中心に書いてます。

明示的なインターフェイス

今読んでいる本で、「明示的なインターフェイス」という表現が出てきたが、馴染みがないので少し調べてみた。

C#実践開発手法 (マイクロソフト公式解説書)
Gary McLean Hall
日経BP
売り上げランキング: 373,052

明示的なインターフェイスの実装 - C# プログラミング ガイド | Microsoft Docs を参考に実施てみた。

 //一般的なインターフェイスの設定
    class Program
    {
        static void Main(string[] args)
        {
            SampleClass sc = new SampleClass();
            IControl ctrl = sc;
            ISurface srfc = sc;

            sc.Paint();
            ctrl.Paint();
            srfc.Paint();
            Console.ReadKey();

        }
    }

    interface IControl
    {
        void Paint();
    }

    interface ISurface
    {
        void Paint();
    }

    class SampleClass : IControl, ISurface
    {
        public void Paint()
        {
            Console.WriteLine("Paint method in SampleClass");
        }
    }

結果は想定通り、3回同じ出力がされた。 Paint method in SampleClass Paint method in SampleClass Paint method in SampleClass

明示的なインターフェースが役に立つのは、インターフェイスで実装しなければならないメソッドのシグネチャがクラスですでに存在していて、シグネチャの競合を回避したい場合。

 //明示的なインタフェースの設定
    class Program
    {
        static void Main(string[] args)
        {
            SampleClass sc = new SampleClass();
            IControl ctrl = sc;
            ISurface srfc = sc;

            sc.Paint();
            ctrl.Paint();
            srfc.Paint();
            Console.ReadKey();

        }
    }

    interface IControl
    {
        void Paint();
    }

    interface ISurface
    {
        void Paint();
    }

    class SampleClass : IControl, ISurface
    {
        public void Paint()
        {
            Console.WriteLine("Paint method in SampleClass");
        }

        void IControl.Paint() //インターフェイスを指定してメソッドを定義
        {
            Console.WriteLine("IContral.Paint");
        }

        void ISurface.Paint() //インターフェイスを指定してメソッドを定義
        {
            Console.WriteLine("ISurface.Paint");
        }
    }

結果は Paint method in SampleClass IContral.Paint ISurface.Paint と、クラスに定義したPaint()は暗黙的なメソッドを。インターフェイスを指定したメソッドはそれぞれ別のメソッドを呼び出している。

また、インターフェイスを継承したクラス内に、明示的な実装だけをしているなかで、インターフェイスではなく、クラスを参照型として 利用するとコンパイルエラーが発生する

 //明示的なインタフェースの設定
    class Program
    {
        static void Main(string[] args)
        {
            SampleClass sc = new SampleClass();
            IControl ctrl = sc;
            ISurface srfc = sc;

            Test test = new Test(sc, ctrl);

            //sc.Paint();
            ctrl.Paint();
            srfc.Paint();
            Console.ReadKey();

        }
    }

    interface IControl
    {
        void Paint();
    }

    interface ISurface
    {
        void Paint();
    }

    class SampleClass : IControl, ISurface
    {
        //public void Paint()
        //{
        //    Console.WriteLine("Paint method in SampleClass");
        //}

        void IControl.Paint() //インターフェイスを指定してメソッドを定義
        {
            Console.WriteLine("IContral.Paint");
        }

        void ISurface.Paint() //インターフェイスを指定してメソッドを定義
        {
            Console.WriteLine("ISurface.Paint");
        }
    }

    class Test
    {
        public Test(SampleClass sampleclass, IControl control)
        {
            sampleclass.Paint(); // これがエラー

            control.Paint();
        }
    }

エラー CS1061 'SampleClass' に 'Paint' の定義が含まれておらず、型 'SampleClass' の最初の引数を受け付けるアクセス可能な拡張メソッド 'Paint' が見つかりませんでした。using ディレクティブまたはアセンブリ参照が不足していないかを確認してください。 ClearInterface C:\Users\user\source\repos\ClearInterface\ClearInterface\Program.cs 60 アクティブ

インターフェイスを継承するが、同じシグネチャのメソッドで処理の中身を変更したい場合に利用できるようである。(競合の回避)

オーバーライドしているわけではなく、インターフェイスで別々に定義していて、実装するクラスで意味合いをそれぞれ変えたい場合に 使えるのだろう。

使いどころがいまいちわからないが、実装クラスからどのインターフェイスを利用しているのかを明示的に使い分けたいときに利用するのだろう。

3章のデザインパターンに読書は続く・・