インターフェイスのメソッドのデフォルト実装 - C#

C#のインターフェイスのメソッドのデフォルト実装のコードを紹介します。

概要

インターフェイスを定義した場合、インターフェイスは完全な抽象クラスのため、基本的にはインターフェイスに定義されている すべての抽象メソッドをインターフェイスを継承した実装クラスで実装する必要があります。
しかし、用途によっては、すべてのインターフェイスのクラスを実装せずに実装クラスを利用したい場合があります。
インターフェイスのメソッドのデフォルト実装の機能を利用すると、メソッドの実装を用意しなくてもインターフェイス実装クラスを利用できるようになります。

プログラム例

UI

下図のフォームを作成します。ボタンとテキストボックスを配置します。

コード

下記コードを記述します。
IMyInterface1.cs
namespace InterfaceDefaultImplement
{
  internal interface IMyInterface1
  {
    public int Proc1();
    public int Proc2()
    {
      return 0;
    }
  }
}
MyClass1.cs
namespace InterfaceDefaultImplement
{
  internal class MyClass1:IMyInterface1
  {
    public int Proc1()
    {
      return 100;
    }
  }
}
フォームのコード (FormInterfaceDefaultImplement.cs)
namespace InterfaceDefaultImplement
{
  public partial class FormInterfaceDefaultImplement : Form
  {
    public FormInterfaceDefaultImplement()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      MyClass1 mc1 = new MyClass1();

      textBox1.Text += string.Format("Proc1 value:{0:d}", mc1.Proc1());
    }
  }
}

解説

IMyInterface1では、Proc1, Proc2 2つのメソッドが宣言されています。Proc2にはメソッドのデフォルト実装が記述されており、0を返すデフォルト実装あります。 そのため、MyClass1ではProc1のみを実装すれば、MyClass1 が利用できる状態になります。

実行結果

プロジェクトを実行します。下図のウィンドウが表示されます。


[button1]ボタンをクリックします。Proc1()メソッドが呼び出され、Proc1の戻り値の値"100"がテキストボックスに表示されます。


Proc2()がデフォルト実装されたメソッドのため、Proc2の実装をクラスで記述しなくても、MyClassを利用できる動作が確認できました。

補足

なお、MyClass1オブジェクトから Proc2メソッドを呼び出すことはできません。
次のコードはビルドエラーになります。
namespace InterfaceDefaultImplement
{
  public partial class FormInterfaceDefaultImplement : Form
  {
    public FormInterfaceDefaultImplement()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      MyClass1 mc1 = new MyClass1();

      textBox1.Text += string.Format("Proc1 value:{0:d}", mc1.Proc1());
      textBox1.Text += string.Format("Proc2 value:{0:d}", mc1.Proc2());
    }
  }
}

ビルドすると次のエラーが発生します。
インターフェイスを実装したクラス(MyClass1)からデフォルト実装のメソッドを呼び出すことはできないようです。
エラーメッセージ
CS1061 : 'MyClass1' に 'Proc2' の定義が含まれておらず、型 'MyClass1' の最初の引数を受け付けるアクセス可能な拡張メソッド 'Proc2' が見つかりませんでした。 using ディレクティブまたはアセンブリ参照が不足していないことを確認してください

デフォルト実装を呼び出す方法

MyClass1オブジェクトから直接デフォルト実装を呼び出すことはできませんが、インターフェイス型にキャストするとデフォルト実装のメソッドを呼び出すことができます。
フォームを次のコードに変更します。
namespace InterfaceDefaultImplement
{
  public partial class FormInterfaceDefaultImplement : Form
  {
    public FormInterfaceDefaultImplement()
    {
      InitializeComponent();
    }

    private void button2_Click(object sender, EventArgs e)
    {
      MyClass1 mc1 = new MyClass1();

      textBox1.Text += string.Format("Proc1 value:{0:d}\r\n", mc1.Proc1());

      IMyInterface1 imi1 = (IMyInterface1)mc1;
      textBox1.Text += string.Format("Proc2 value:{0:d}\r\n", imi1.Proc2());
    }
  }
}

プロジェクトを実行し[button2]をクリックすると、下図の表示になります。インターフェイスのProc2() メソッドの デフォルト実装が呼び出されて動作していることが確認できます。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2022-05-26
iPentec all rights reserverd.