明示的なインターフェイスの実装 (C# プログラミング ガイド)

シグネチャが同じメンバーが含まれる 2 つのインターフェイスをあるクラスが実装する場合、そのクラスでそのメンバーを実装することで、実装としてそのメンバーが両方のインターフェイスで使用されます。 次の例では、Paint のすべての呼び出しで同じメソッドが呼び出されます。 この最初のサンプルでは、型が定義されます。

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

次のサンプルでは、メソッドが呼び出されます。

SampleClass sample = new SampleClass();
IControl control = sample;
ISurface surface = sample;

// The following lines all call the same method.
sample.Paint();
control.Paint();
surface.Paint();

// Output:
// Paint method in SampleClass
// Paint method in SampleClass
// Paint method in SampleClass

ただし、両方のインターフェイスに対して同じ実装を呼び出さないようにすることもできます。 使用中のインターフェイスに応じて異なる実装を呼び出すには、インターフェイス メンバーを明示的に実装します。 明示的なインターフェイスの実装は、指定されたインターフェイスを介してのみ呼び出されるクラス メンバーです。 インターフェイスの名前とピリオドを使ってプレフィックスを付けて、クラス メンバーに名前を付けます。 次に例を示します。

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

クラス メンバー IControl.PaintIControl インターフェイス経由でのみ利用できます。ISurface.PaintISurface 経由でのみ利用できます。 いずれのメソッド実装も個別であり、どちらもクラスで直接利用できません。 次に例を示します。

SampleClass sample = new SampleClass();
IControl control = sample;
ISurface surface = sample;

// The following lines all call the same method.
//sample.Paint(); // Compiler error.
control.Paint();  // Calls IControl.Paint on SampleClass.
surface.Paint();  // Calls ISurface.Paint on SampleClass.

// Output:
// IControl.Paint
// ISurface.Paint

2 つのインターフェイスで、それぞれが同じ名前の別のメンバー (プロパティやメソッドなど) を宣言するような場合の解決には、明示的な実装も利用されます。 両方のインターフェイスを実装するには、コンパイラ エラーを回避するために、クラスはプロパティ P、メソッド P、または両方に明示的な実装を利用する必要があります。 次に例を示します。

interface ILeft
{
    int P { get;}
}
interface IRight
{
    int P();
}

class Middle : ILeft, IRight
{
    public int P() { return 0; }
    int ILeft.P { get { return 0; } }
}

明示的なインターフェイスの実装には、定義されている型のメンバーとしてアクセスできないため、アクセス修飾子がありません。 代わりに、インターフェイスのインスタンスを介して呼び出された場合にのみアクセスできます。 明示的なインターフェイスの実装にアクセス修飾子を指定すると、コンパイラ エラー CS0106 が発生します。 詳細については、「interface (C# リファレンス)」を参照してください。

C# 8.0 以降では、インターフェイスで宣言されたメンバーの実装を定義できます。 クラスでインターフェイスからメソッド実装が継承される場合、そのメソッドにはインターフェイス型の参照を利用する方法でのみアクセスできます。 継承したメンバーは、パブリック インターフェイスの一部として表示されません。 次のサンプルでは、インターフェイス メソッドの既定の実装が定義されます。

public interface IControl
{
    void Paint() => Console.WriteLine("Default Paint method");
}
public class SampleClass : IControl
{
    // Paint() is inherited from IControl.
}

次のサンプルでは、既定の実装が呼び出されます。

var sample = new SampleClass();
//sample.Paint();// "Paint" isn't accessible.
var control = sample as IControl;
control.Paint();

IControl インターフェイスを実装するあらゆるクラスによって、既定の Paint メソッドをパブリック メソッドか明示的なインターフェイス実装としてオーバーライドできます。

関連項目