インターフェイス - 複数の型の動作を定義する

インターフェイスには、非抽象 class または struct で実装する必要がある、関連する機能のグループに対する定義が含まれます。 インターフェイスを使用すると、実装が必要な static メソッドを定義することができます。 インターフェイスによってメンバーの既定の実装を定義できます。 インターフェイスでは、フィールド、自動実装プロパティ、プロパティに似たイベントなどのインスタンス データを宣言できません。

インターフェイスを使用すると、たとえば、クラス内の複数のソースからの動作を含めることができます。 C# ではクラスの複数の継承がサポートされないため、この機能は重要です。 また、構造体の継承をシミュレートする場合はインターフェイスを使用する必要があります。これは、実際に別の構造体またはクラスから継承することができないためです。

インターフェイスを定義するには、次の例に示すように、interface キーワードを使用します。

interface IEquatable<T>
{
    bool Equals(T obj);
}

インターフェイスの名前を、有効な C# の識別子名にする必要があります。 慣例により、インターフェイス名は大文字の I で始めます。

IEquatable<T> インターフェイスを実装するすべてのクラスまたは構造体は、インターフェイスで指定されたシグネチャに一致する Equals メソッドの定義を含む必要があります。 したがって、IEquatable<T> を実装するクラスが Equals メソッドを含むと想定したうえで、これを使用してクラスの 1 つのインスタンスが同じクラスの別のインスタンスと等しいかどうかを判定できます。

IEquatable<T> の定義は Equals の実装を提供しません。 クラスまたは構造体には複数のインターフェイスを実装できます。ただし、クラスは 1 つのクラスからのみ継承できます。

抽象クラスの詳細については、「抽象クラスとシール クラス、およびクラス メンバー」を参照してください。

インターフェイスには、instance メソッド、プロパティ、イベント、インデクサー、またはこれらの 4 種類のメンバーの任意の組み合わせを含めることができます。 インターフェイスには、静的コンストラクター、フィールド、定数、または演算子を含めることができます。 C# 11 以降では、フィールドではないインターフェイス メンバーは static abstract になることがあります。 インターフェイスには、インスタンス フィールド、インスタンス コンストラクター、またはファイナライザーを含めることができません。 インターフェイス メンバーは、既定ではパブリックであり、publicprotectedinternalprivateprotected internalprivate protected などのアクセシビリティ修飾子を明示的に指定できます。 private メンバーには既定の実装が必要です。

インターフェイスのメンバーを実装するには、実装するクラスの対応するメンバーがパブリックかつ非静的であり、インターフェイスのメンバーと同じ名前およびシグネチャを持つ必要があります。

注意

インターフェイスが静的メンバーを宣言する場合、そのインターフェイスを実装する型でも、同じシグネチャを持つ静的メンバーを宣言できます。 それらは違うものであり、メンバーを宣言する型によって一意に識別されます。 型で宣言された静的メンバーは、インターフェイスで宣言された静的メンバーをオーバーライド "しません"。

インターフェイスを実装するクラスまたは構造体は、インターフェイスに既定の実装が用意されていない場合に、宣言したすべてのメンバーの実装を提供する必要があります。 ただし、基本クラスでインターフェイスが実装される場合、その基本クラスから派生するすべてのクラスはその実装を継承します。

IEquatable<T> インターフェイスを実装する例を次に示します。 実装するクラスの Car は、Equals メソッドの実装を提供する必要があります。

public class Car : IEquatable<Car>
{
    public string? Make { get; set; }
    public string? Model { get; set; }
    public string? Year { get; set; }

    // Implementation of IEquatable<T> interface
    public bool Equals(Car? car)
    {
        return (this.Make, this.Model, this.Year) ==
            (car?.Make, car?.Model, car?.Year);
    }
}

クラスのプロパティとインデクサーでは、インターフェイスに定義されているプロパティまたはインデクサーの追加のアクセサーを定義できます。 たとえば、インターフェイスで get アクセサーを持つプロパティを宣言するとします。 このインターフェイスを実装するクラスでは、get アクセサーと get アクセサーの両方を持つ同じプロパティを宣言できます。 ただし、プロパティまたはインデクサーで明示的な実装を使用する場合は、これらのアクセサーが一致する必要があります。 明示的な実装の詳細については、「明示的なインターフェイス実装」および「インターフェイスのプロパティ」を参照してください。

インターフェイスは、1 つ以上のインターフェイスから継承できます。 派生インターフェイスは、その基本インターフェイスからメンバーを継承します。 派生インターフェイスを実装するクラスでは、派生インターフェイスの基底インターフェイスのすべてのメンバーを含め、派生インターフェイスのすべてのメンバーを実装する必要があります。 そのクラスは、暗黙的に派生インターフェイスまたはその基底インターフェイスのいずれかに変換されます。 クラスは、継承する基底クラス、または他のインターフェイスが継承するインターフェイスを介して、インターフェイスを複数回含めることができます。 ただし、クラスでインターフェイスの実装を提供できるのは 1 回のみであり、それもクラスでクラスの定義の一部としてインターフェイスを宣言する場合 (class ClassName : InterfaceName) に限られます。 インターフェイスを実装する基本クラスを継承することによってインターフェイスを継承する場合、基本クラスは、そのインターフェイスのメンバーの実装を提供します。 ただし、派生クラスでは、継承された実装を使用する代わりに、任意の仮想インターフェイスのメンバーを再実装できます。 インターフェイスにメソッドの既定の実装が宣言されている場合、そのインターフェイスを実装しているクラスにはその実装が継承されます (インターフェイス メンバーの既定の実装にアクセスするには、クラスのインスタンスをインターフェイス型にキャストする必要があります)。

また、基本クラスでは、仮想メンバーを使用して、インターフェイスのメンバーを実装することもできます。 その場合、派生クラスでは、仮想メンバーをオーバーライドすることでインターフェイスの動作を変更できます。 仮想メンバーの詳細については、「ポリモーフィズム」を参照してください。

インターフェイスの概要

インターフェイスは、次の特性を持ちます。

  • 8\.0 よりも前のバージョンの C# では、インターフェイスは抽象メンバーのみを含む抽象基本クラスに似ています。 インターフェイスを実装するクラスまたは構造体では、そのすべてのメンバーを実装する必要があります。
  • C# 8.0 以降では、そのメンバーの一部またはすべての既定の実装をインターフェイスで定義できます。 インターフェイスを実装するクラスまたは構造体では、既定の実装を持つメンバーを実装する必要はありません。 詳細については、既定のインターフェイス メソッドに関する記事をご覧ください。
  • インターフェイスを直接インスタンス化することはできません。 そのメンバーは、インターフェイスを実装する任意のクラスまたは構造体によって実装されます。
  • クラスまたは構造体は、複数のインターフェイスを実装できます。 クラスは、基本クラスを継承する一方で、1 つまたは複数のインターフェイスを実装できます。