interface (Odwołanie w C#)
Interfejs definiuje kontrakt. Każdy class
element lub struct
record
implementujący ten kontrakt musi zapewnić implementację elementów członkowskich zdefiniowanych w interfejsie. Interfejs może definiować domyślną implementację dla elementów członkowskich. Może również definiować static
elementy członkowskie w celu zapewnienia jednej implementacji dla typowych funkcji. Począwszy od języka C# 11, interfejs może definiować static abstract
elementy członkowskie lub static virtual
zadeklarować, że typ implementujący musi podać zadeklarowane elementy członkowskie. Zazwyczaj metody deklarują, static virtual
że implementacja musi definiować zestaw przeciążonych operatorów.
W poniższym przykładzie klasa ImplementationClass
musi zaimplementować metodę o nazwie SampleMethod
, która nie ma parametrów i zwraca wartość void
.
Aby uzyskać więcej informacji i przykładów, zobacz Interfejsy.
Interfejs najwyższego poziomu, zadeklarowany w przestrzeni nazw, ale nie zagnieżdżony wewnątrz innego typu, można zadeklarować public
lub internal
. Wartość domyślna to internal
. Zagnieżdżone deklaracje interfejsu, zadeklarowane wewnątrz innego typu, można zadeklarować przy użyciu dowolnego modyfikatora dostępu.
Elementy członkowskie interfejsu bez implementacji nie mogą zawierać modyfikatora dostępu. Członkowie z domyślną implementacją mogą zawierać dowolny modyfikator dostępu.
Przykładowy interfejs
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();
}
}
Interfejs może być elementem członkowskim przestrzeni nazw lub klasy. Deklaracja interfejsu może zawierać deklaracje (podpisy bez żadnej implementacji) następujących elementów członkowskich:
- Metody
- Właściwości
- Indexers (Indeksatory)
- Wydarzenia
Domyślne elementy członkowskie interfejsu
Powyższe deklaracje składowe zwykle nie zawierają treści. Element członkowski interfejsu może zadeklarować treść. Elementy członkowskie w interfejsie są domyślną implementacją. Elementy członkowskie z ciałami umożliwiają interfejsowi zapewnienie implementacji "domyślnej" dla klas i struktur, które nie zapewniają zastępowania implementacji.
Ważne
Dodanie domyślnych elementów członkowskich wymusza każdą ref struct
implementację interfejsu w celu dodania jawnej deklaracji tego elementu członkowskiego.
Interfejs może obejmować:
- Stałe
- Operatory
- Konstruktor statyczny.
- Typy zagnieżdżone
- Pola statyczne, metody, właściwości, indeksatory i zdarzenia
- Deklaracje składowe przy użyciu jawnej składni implementacji interfejsu.
- Modyfikatory dostępu jawnego (domyślny dostęp to
public
).
Statyczne abstrakcyjne i wirtualne elementy członkowskie
Począwszy od języka C# 11, interfejs może deklarować static abstract
i static virtual
składowe dla wszystkich typów składowych z wyjątkiem pól. Interfejsy mogą zadeklarować, że typy implementujące muszą definiować operatory lub inne statyczne elementy członkowskie. Ta funkcja umożliwia ogólne algorytmy określania zachowania przypominającego liczbę. Przykłady można zobaczyć w typach liczbowych w środowisku uruchomieniowym platformy .NET, takich jak System.Numerics.INumber<TSelf>. Te interfejsy definiują typowe operatory matematyczne implementowane przez wiele typów liczbowych. Kompilator musi rozpoznawać wywołania metod static virtual
i w static abstract
czasie kompilacji. Metody static virtual
i static abstract
zadeklarowane w interfejsach nie mają mechanizmu wysyłania środowiska uruchomieniowego analogicznego do virtual
lub abstract
metod zadeklarowanych w klasach. Zamiast tego kompilator używa informacji o typie dostępnych w czasie kompilacji. W związku z static virtual
tym metody są prawie wyłącznie deklarowane w interfejsach ogólnych. Ponadto większość interfejsów, które deklarują metody lub deklarująstatic virtual
, że jeden z parametrów typu musi implementować zadeklarowany interfejs.static abstract
Na przykład interfejs deklaruje, INumber<T>
że T
musi implementować INumber<T>
element . Kompilator używa argumentu typu do rozpoznawania wywołań metod i operatorów zadeklarowanych w deklaracji interfejsu. Na przykład int
typ implementuje INumber<int>
wartość . Gdy parametr T
typu oznacza argument int
typu , static
wywoływane są elementy członkowskie zadeklarowane int
na. Alternatywnie, gdy double
jest argumentem typu, static
elementy członkowskie zadeklarowane w typie double
są wywoływane.
Ważne
Wysyłanie metody dla static abstract
metod zadeklarowanych w interfejsach i static virtual
jest rozpoznawane przy użyciu typu czasu kompilacji wyrażenia. Jeśli typ środowiska uruchomieniowego wyrażenia pochodzi z innego typu czasu kompilacji, wywoływane będą metody statyczne w typie podstawowym (czas kompilacji).
Tę funkcję można wypróbować, pracując z samouczkiem dotyczącym statycznych abstrakcyjnych elementów członkowskich w interfejsach.
Dziedziczenie interfejsu
Interfejsy mogą nie zawierać stanu wystąpienia. Pola statyczne są teraz dozwolone, ale pola wystąpień nie są dozwolone w interfejsach. Właściwości automatyczne wystąpienia nie są obsługiwane w interfejsach, ponieważ niejawnie deklarują ukryte pole. Ta reguła ma subtelny wpływ na deklaracje właściwości. W deklaracji interfejsu poniższy kod nie deklaruje automatycznie zaimplementowanej właściwości, tak jak w obiekcie class
lub struct
. Zamiast tego deklaruje właściwość, która nie ma implementacji domyślnej, ale musi być zaimplementowana w dowolnym typie, który implementuje interfejs:
public interface INamed
{
public string Name {get; set;}
}
Interfejs może dziedziczyć z co najmniej jednego interfejsu podstawowego. Gdy interfejs dziedziczy z innego interfejsu, typ implementowania interfejsu pochodnego musi implementować wszystkie elementy członkowskie w interfejsach podstawowych, a także te zadeklarowane w interfejsie pochodnym, jak pokazano w poniższym kodzie:
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() { }
}
Gdy interfejs zastępuje metodę zaimplementowaną w interfejsie podstawowym, musi używać jawnej składni implementacji interfejsu.
Gdy lista typów podstawowych zawiera klasę bazową i interfejsy, klasa bazowa musi znajdować się na liście jako pierwsza.
Klasa, która implementuje interfejs, może jawnie implementować elementy członkowskie tego interfejsu. Jawnie zaimplementowany element członkowski nie może być dostępny za pośrednictwem wystąpienia klasy, ale tylko za pośrednictwem wystąpienia interfejsu. Ponadto dostęp do domyślnych elementów członkowskich interfejsu można uzyskać tylko za pośrednictwem wystąpienia interfejsu.
Aby uzyskać więcej informacji na temat jawnej implementacji interfejsu, zobacz Jawna implementacja interfejsu.
Przykładowa implementacja interfejsu
W poniższym przykładzie pokazano implementację interfejsu. W tym przykładzie interfejs zawiera deklarację właściwości, a klasa zawiera implementację. Każde wystąpienie klasy, która implementuje, ma właściwości x
liczb całkowitych IPoint
i 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
specyfikacja języka C#
Aby uzyskać więcej informacji, zobacz sekcję Interfejsy specyfikacji języka C#, specyfikację funkcji dla C# 8 — domyślnych elementów członkowskich interfejsu oraz specyfikację funkcji dla języka C# 11 — statycznych elementów abstrakcyjnych w interfejsach