rksoftware

Visual Studio とか C# とかが好きです

C# 8 の確認 - 既定のインターフェイス メソッド

今回は 既定のインターフェイス メソッド 。結構話題だったので名前は聞いたことがあるという方もいるのではないでしょうか?

公式はこちら

このブログでの目次?はこちら

インターフェイスに実装がもてる

ここでは Method2 に 2 を返すという実装がされています。

interface IA
{
    int Method1();
    int Method2() => 2;
}

インターフェイスの実装クラスでは、Method2 を実装しなくて良い(してもよい)。

 class A : IA
 {
     public int Method1() => 1;
 }

この場合、Method2 は IA 型の変数でしか使えません。
次のコードは A 型なのでコンパイルエラーになります。

var a = new A();
Console.WriteLine($"Method1 = {a.Method1()}, Method2 = {a.Method2()}");

エラー CS1061 'A' に 'Method2' の定義が含まれておらず、型 'A' の最初の引数を受け付けるアクセス可能な拡張メソッド 'Method2' が見つかりませんでした。using ディレクティブまたはアセンブリ参照が不足していないことを確認してください。

次のように IA 型にキャストすると Method2 が使えるようになります。

var a = new A();
var ia = (IA)a;
Console.WriteLine($"Method1 = {ia.Method1()}, Method2 = {ia.Method2()}");

ダイヤモンド継承

多重継承も OK です。インタフェースの型でしか使えないので混ざりません。

class Program
{
    interface IA
    {
        int Method1();
        int Method2() => 2;
    }

    interface IB
    {
        int Method1();
        int Method2() => 3;
    }

    class A : IA, IB
    {
        public int Method1() => 1;
    }

    static void Main(string[] args)
    {
        var a = new A();
        // 2 が表示される
        Console.WriteLine($"Method1 = {a.Method1()}, Method2 = {((IA)a).Method2()}");

        // 3 が表示される
        Console.WriteLine($"Method1 = {a.Method1()}, Method2 = {((IB)a).Method2()}");
    }
}

クラスで実装をすると常にクラスの実装が使われる

クラスで実装をすることもできます。
その場合はインタフェースの型で使ったとしても常にクラスの実装が使われます。

class Program
{
    interface IA
    {
        int Method1();
        int Method2() => 2;
    }

    interface IB
    {
        int Method1();
        int Method2() => 3;
    }

    class A : IA, IB
    {
        public int Method1() => 1;
        public int Method2() => 1;
    }

    static void Main(string[] args)
    {
        var a = new A();
        // すべて 1 が出力される
        Console.WriteLine($"Method1 = {a.Method1()}, Method2 = {a.Method2()}");
        Console.WriteLine($"Method1 = {a.Method1()}, Method2 = {((IA)a).Method2()}");
        Console.WriteLine($"Method1 = {a.Method1()}, Method2 = {((IB)a).Method2()}");
    }
}

このコードでは、クラスで実装しているので全て 1 が出力されます。