インターフェイスによりコントラクトが定義されます。 そのコントラクトを実装する class、 record、または struct は、インターフェイスで定義されたメンバーの実装を提供する必要があります。
インターフェイスは、メンバーの 既定の実装 を定義できます。 また、 static メンバーを定義して、共通機能の単一の実装を提供することもできます。
インターフェイスは、 static abstract または static virtual メンバーを定義して、実装する型が宣言されたメンバーを提供する必要があることを宣言できます。 通常、static virtual メソッドでは、実装でオーバーロードされた演算子のセットを定義する必要があることを宣言します。
次の例の ImplementationClass クラスは、SampleMethod を返す、パラメーターのない void メソッドを実装する必要があります。
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();
}
}
使用例を含む詳細については、「インターフェイス」を参照してください。
アクセス修飾子
インターフェイスには、名前空間またはクラスのメンバーを指定できます。 名前空間で宣言されているが、別の型内に入れ子になっていない最上位のインターフェイスは、public または internal として宣言できます。 既定値は、internal です。 別の型内で宣言された入れ子になったインターフェイス宣言は、任意のアクセス修飾子を使用して宣言できます。
実装 のない インターフェイス メンバー (抽象メンバー) は暗黙的に public され、他のアクセス修飾子を持つことはありません。 既定の実装 を持つ インターフェイス メンバーは、アクセス修飾子が指定されていない場合は既定で private されますが、任意のアクセス修飾子 (public、 private、 protected、または internal) で宣言できます。
インターフェイス メンバー
インターフェイス宣言には、次のメンバーを含めることができます。
- メソッド。
- プロパティ。
- インデクサー。
- イベント。
- 定数。
- 演算子。
- 静的コンストラクター。
- 入れ子になった型。
- 静的フィールド、メソッド、プロパティ、インデクサー、およびイベント。
- 明示的なアクセス修飾子 (抽象メソッドの既定のアクセスは
public)。
既定のインターフェイス メンバー
メンバー宣言には通常、本文は含まれませんが、インターフェイス メンバーは本文を宣言できます。 インターフェイス内のメンバー本文は、"既定の実装" です。 本文のあるメンバーでは、実装が��ーバーライドされないクラスおよび構造体に "既定の" 実装を与えることがインターフェイスに許可されます。
重要
既定のインターフェイス メンバーを追加すると、インターフェイスを実装する ref struct がそのメンバーの明示的な宣言を追加しなければならなくなります。
静的抽象および仮想メンバー
インターフェイスは、フィールドを除くすべてのメンバー型の 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> インターフェイスでは、T が INumber<T> を実装する必要があることが宣言されます。 コンパイラでは、型引数を使用して、インターフェイス宣言で宣言されているメソッドと演算子への呼び出しを解決します。 たとえば、int 型では INumber<int> が実装されます。 型パラメーター T が型引数 int を表す場合、static で宣言されている int メンバーが呼び出されます。 または、double が型引数である場合、static 型で宣言された double メンバーが呼び出されます。
重要
インターフェイスで宣言された static abstract および static virtual メソッドのメソッド ディスパッチは、式のコンパイル時の型を使用して解決されます。 式のランタイム型が別のコンパイル時型から派生している場合は、基本 (コンパイル時) 型の静的メソッドが呼び出されます。
この機能は、インターフェイスの静的抽象メンバーに関するチュートリアルで試すことができます。
インターフェイスの継承
インターフェイスにインスタンス状態を含めることはできません。 静的フィールドが許可されるようになりましたが、インスタンス フィールドはインターフェイスでは許可されません。
インスタンスの自動プロパティはインターフェイスではサポートされていません。暗黙的に隠しフィールドが宣言されるためです。 このルールは、プロパティの宣言に微細な影響を与えます。 インターフェイス宣言では、次のコードは、 class または structの場合と同様に、自動的に実装されるプロパティを宣言しません。 その代わり、既定の実装が与えられないが、インターフェイスを実装する何らかの型で実装する必要があるプロパティが宣言されます。
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# 言語仕様の Interfaces セクションと、インターフェイスの静的抽象メンバーの機能仕様を参照してください。
関連項目
.NET