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

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

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

Члены интерфейса по умолчанию

Эти предыдущие объявления элементов обычно не содержат тела. Элемент интерфейса может объявлять текст. Тела членов в интерфейсе являются реализацией по умолчанию. Члены с телом позволяют интерфейсу предоставлять реализацию по умолчанию для классов и структур, которые не предоставляют реализацию с переопределением. Интерфейс может включать:

Статические абстрактные и виртуальные элементы

Начиная с 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;}
}

Интерфейс может наследовать от одного или нескольких базовых интерфейсов. Когда интерфейс переопределяет метод, реализованный в базовом интерфейсе, он должен использовать синтаксис явной реализации интерфейса.

Если список базовых типов содержит базовый класс и интерфейсы, базовый класс должен стоять первым в списке.

Класс, реализующий интерфейс, может явно реализовывать члены этого интерфейса. Доступ к явно реализованном члену можно получить не через экземпляр класса, а только через экземпляр интерфейса . Кроме того, обращение к членам интерфейса по умолчанию можно осуществлять только через экземпляр интерфейса.

Дополнительные сведения о явной реализации интерфейса см. в статье Явная реализация интерфейса.

Пример реализации интерфейса

В следующем примере показана реализация интерфейса. В этом примере интерфейс содержит объявление свойства, а класс содержит реализацию. Любой экземпляр класса, который реализует 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 — статические абстрактные члены в интерфейсах.

См. также раздел