interface (C# リファレンス)
インターフェイスによりコントラクトが定義されます。 そのコントラクトを実装するすべての class
、record
、struct
では、インターフェイスで定義されているメンバーの実装を提供する必要があります。 インターフェイスによってメンバーの既定の実装を定義できます。 共通の機能を 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
がそのメンバーの明示的な宣言を追加しなければならなくなります。
インターフェイスには、次のものが含まれます。
- 定数
- オペレーター
- 静的コンストラクター。
- 入れ子にされた型
- 静的フィールド、メソッド、プロパティ、インデクサー、イベント
- 明示的なインターフェイス実装構文を使用するメンバー宣言。
- 明示的なアクセス修飾子 (既定のアクセスは
public
)。
静的抽象および仮想メンバー
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>
インターフェイスでは、T
が INumber<T>
を実装する必要があることが宣言されます。 コンパイラでは、型引数を使用して、インターフェイス宣言で宣言されているメソッドと演算子への呼び出しを解決します。 たとえば、int
型では INumber<int>
が実装されます。 型パラメーター T
が型引数 int
を表す場合、int
で宣言されている static
メンバーが呼び出されます。 または、double
が型引数である場合、double
型で宣言された static
メンバーが呼び出されます。
重要
インターフェイスで宣言された 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# 言語仕様のインターフェイス セクション、C# 8 - 既定のインターフェイス メンバーの機能仕様、C# 11 - インターフェイスの静的抽象メンバーの機能仕様を参照してください。
関連項目
.NET