interface (C# リファレンス)

インターフェイスによりコントラクトが定義されます。 そのコントラクトを実装するすべての classrecordstruct では、インターフェイスで定義されているメンバーの実装を提供する必要があります。 インターフェイスによってメンバーの既定の実装を定義できます。 共通の機能を 1 回で実装する目的で static メンバーも定義できます。 C# 11 以降では、インターフェイスで static abstract または static virtual メンバーを定義し、実装型が宣言されたメンバーを提供する必要があることを宣言できます。 通常、static virtual メソッドでは、実装でオーバーロードされた演算子のセットを定義する必要があることを宣言します。

次の例の ImplementationClass クラスは、SampleMethod を返す、パラメーターのない void メソッドを実装する必要があります。

使用例を含む詳細については、「インターフェイス」を参照してください。

名前空間で宣言されているが、別の型内に入れ子になっていない最上位のインターフェイスは、public または internal として宣言できます。 既定値は、internal です。 入れ子になったインターフェイス宣言 (別の型内で宣言されているもの) は、任意のアクセス修飾子を使用して宣言できます。

実装のないインターフェイス メンバーには、アクセス修飾子を含めることはできません。 既定の実装を持つメンバーには、任意のアクセス修飾子を含めることができます。

インターフェイスの例

interface ISampleInterface
{
    void SampleMethod();
}

class ImplementationClass : ISampleInterface
{
    // Explicit interface member implementation:
    void ISampleInterface.SampleMethod()
    {
        // Method implementation.
    }

    static void Main()
    {
        // Declare an interface instance.
        ISampleInterface obj = new ImplementationClass();

        // Call the member.
        obj.SampleMethod();
    }
}

インターフェイスには、名前空間またはクラスのメンバーを指定できます。 インターフェイス宣言には、次のメンバーの宣言を含めることができます (実装なしのシグネチャ)。

既定のインターフェイス メンバー

通常、これらのメンバー宣言には、本文が含まれません。 インターフェイス メンバーで本文を宣言できます。 インターフェイス内のメンバー本文は、"既定の実装" です。 本文のあるメンバーでは、実装がオーバーライドされないクラスおよび構造体に "既定の" 実装を与えることがインターフェイスに許可されます。

重要

既定のインターフェイス メンバーを追加すると、インターフェイスを実装する ref struct がそのメンバーの明示的な宣言を追加しなければならなくなります。

インターフェイスには、次のものが含まれます。

静的抽象および仮想メンバー

C# 11 以降では、フィールドを除くあらゆるメンバー型に対してインターフェイスで static abstract および static virtual メンバーを宣言できます。 インターフェイスでは、実装型が演算子またはその他の静的メンバーを定義する必要があることを宣言できます。 この機能を使用すると、汎用アルゴリズムで数字のような動作を指定できます。 .NET ランタイムの数値型で例を確認できます (System.Numerics.INumber<TSelf> など)。 これらのインターフェイスでは、多くの数値型によって実装される一般的な算術演算子が定義されます。 コンパイラでは、static virtual および static abstract メソッドへの呼び出しをコンパイル時に解決する必要があります。 インターフェイスで宣言された static virtual および static abstract メソッドには、クラスで宣言された virtual または abstract メソッドに似たランタイム ディスパッチ メカニズムがありません。 代わりに、コンパイラでは、コンパイル時に利用できる型情報が使用されます。 したがって、static virtual メソッドは、ほぼ例外なくジェネリック インターフェイスで宣言されます。 さらに、static virtual または static abstract メソッドを宣言するほとんどのインターフェイスでは、型パラメーターの 1 つが宣言されたインターフェイスを実装する必要があることが宣言されます。 たとえば、INumber<T> インターフェイスでは、TINumber<T> を実装する必要があることが宣言されます。 コンパイラでは、型引数を使用して、インターフェイス宣言で宣言されているメソッドと演算子への呼び出しを解決します。 たとえば、int 型では INumber<int> が実装されます。 型パラメーター T が型引数 int を表す場合、int で宣言されている static メンバーが呼び出されます。 または、double が型引数である場合、double 型で宣言された static メンバーが呼び出されます。

重要

インターフェイスで宣言された static abstract および static virtual メソッドのメソッド ディスパッチは、式のコンパイル時の型を使用して解決されます。 式のランタイム型が別のコンパイル時型から派生している場合は、基本 (コンパイル時) 型の静的メソッドが呼び出されます。

この機能は、インターフェイスの静的抽象メンバーに関するチュートリアルで試すことができます。

インターフェイスの継承

インターフェイスには、インスタンスの状態を含めることはできません。 静的フィールドが許可されるようになりましたが、インスタンス フィールドはインターフェイスでは許可されません。 インスタンスの自動プロパティはインターフェイスではサポートされていません。暗黙的に隠しフィールドが宣言されるためです。 このルールは、プロパティの宣言に微細な影響を与えます。 インターフェイス宣言では、次のコードによって、classstruct の場合のように自動実装プロパティが宣言されることはありません。 その代わり、既定の実装が与えられないが、インターフェイスを実装する何らかの型で実装する必要があるプロパティが宣言されます。

public interface INamed
{
  public string Name {get; set;}
}

インターフェイスは、1 つ以上の基底インターフェイスから継承できます。 インターフェイスが別のインターフェイスから継承される場合、派生インターフェイスを実装する型は、次のコードに示すように、基本インターフェイスのすべてのメンバーと、派生インターフェイスで宣言されたメンバーを実装する必要があります。

public interface I1
{
    void M1();
}

public interface I2 : I1
{
    void M2();
}

public class C : I2
{
    // implements I1.M1
    public void M1() { }
    // implements I2.M2
    public void M2() { }
}

あるインターフェイスで基底インターフェイスに実装されているメソッドがオーバーライドされるとき、そのインターフェイスでは明示的なインターフェイス実装構文を使用する必要があります。

基本型のリストに基底クラスとインターフェイスが含まれる場合は、基底クラスがリストの最初に表示されます。

インターフェイスを実装するクラスは、そのインターフェイスのメンバーを明示的に実装できます。 明示的に実装されているメンバーには、クラス インスタンスではアクセスできません。インターフェイスのインスタンスを使用した場合にのみアクセスできます。 また、既定のインターフェイス メンバーには、インターフェイスのインスタンス経由でのみアクセスできます。

明示的なインターフェイス実装の詳細については、「明示的なインターフェイスの実装」を参照してください。

インターフェイスの実装例

ここでは、インターフェイスの実装例を示します。 この例では、インターフェイスにプロパティ宣言が含まれ、クラスに実装が含まれます。 IPoint を実装するクラスのインスタンスには、整数プロパティ x および y が含まれています。

interface IPoint
{
    // Property signatures:
    int X { get; set; }

    int Y { get; set; }

    double Distance { get; }
}

class Point : IPoint
{
    // Constructor:
    public Point(int x, int y)
    {
        X = x;
        Y = y;
    }

    // Property implementation:
    public int X { get; set; }

    public int Y { get; set; }

    // Property implementation
    public double Distance =>
       Math.Sqrt(X * X + Y * Y);
}

class MainClass
{
    static void PrintPoint(IPoint p)
    {
        Console.WriteLine("x={0}, y={1}", p.X, p.Y);
    }

    static void Main()
    {
        IPoint p = new Point(2, 3);
        Console.Write("My Point: ");
        PrintPoint(p);
    }
}
// Output: My Point: x=2, y=3

C# 言語仕様

詳細については、C# 言語仕様インターフェイス セクション、C# 8 - 既定のインターフェイス メンバーの機能仕様、C# 11 - インターフェイスの静的抽象メンバーの機能仕様を参照してください。

関連項目