Поделиться через


interface (справочник по C#)

Интерфейс определяет контракт. record Любой classили struct реализующий этот контракт должен предоставлять реализацию элементов, определенных в интерфейсе. Интерфейс может определить реализацию по умолчанию для членов. Он также может определять члены 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 Например, интерфейс объявляет, 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;}
}

Интерфейс может наследовать от одного или нескольких базовых интерфейсов. При наследовании интерфейса от другого интерфейса тип, реализующий производный интерфейс, должен реализовать все члены базовых интерфейсов, а также те, которые объявлены в производном интерфейсе, как показано в следующем коде:

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 — статические абстрактные элементы в интерфейсах.

См. также