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


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

Интерфейс определяет контракт. Любой class, recordили struct который реализует этот контракт, должен предоставить реализацию элементов, определенных в интерфейсе.

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

Интерфейс может определить или static virtual членыstatic abstract, чтобы объявить, что тип реализации должен предоставлять объявленные члены. Как правило, методы объявляют, 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, илиprivateprotectedinternal).

Члены интерфейса

Объявление интерфейса может содержать следующие элементы:

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

Объявления членов обычно не содержат текст, однако член интерфейса может объявить тело. Органы-члены в интерфейсе — это реализация по умолчанию. Члены с телом позволяют интерфейсу предоставлять реализацию по умолчанию для классов и структур, которые не предоставляют реализацию с переопределением.

Внимание

Добавление элементов интерфейсов по умолчанию заставляет любой ref struct , реализующий интерфейс, добавить явное объявление этого элемента.

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

Интерфейс может объявлять и static virtual члены static abstract для всех типов элементов, кроме полей. Интерфейсы могут объявлять, что реализация типов должна определять операторы или другие статические члены. Эта функция позволяет универсальным алгоритмам указывать поведение, подобное числу. Примеры можно увидеть в числовых типах во время выполнения .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# и спецификации компонентов для статических абстрактных элементов в интерфейсах.

См. также