Csharp interface для чего он нужен

В статье Абстрактные классы, методы и свойства был рассмотрен пример наследования от абстрактного класса классов-потомков и использования абстрактных методов, как шаблонов для реализации их в классах-потомках. Было отмечено, что другой вариант реализации — использование интерфейсов.

Они позволяют обойтись без абстрактных классов, но позволяют контролировать работу методов родственных классов. Рассмотрим тот же пример — Правильный многоугольник. Разобрав его, вам станут понятны интерфейсы и их назначение в программировании в среде .Net Framework.

Пример использования интерфейса

В пространство ИнтерфейсФигур добавим новый элемент — интерфейс IFigureInfo. Это можно сделать через Меню Проект/Добавить новый элемент/Интерфейс или Ctrl+Shift+A/Интерфейс (тогда добавится файл Interface1.cs) со следующим содержанием или же вставить это объявление в текст основного кода приложения (см. ниже).

Это означает, что во всех классах, поддерживающих этот интерфейс, должны быть реализованы эти два метода без параметров, возвращающих тип double.

Создадим три независимых класса: Circle, Square, Triangle. У каждого из этих классов есть свой набор полей и методов, связанных с их особенностями, в том числе — характерный размер — Length. Для круга это, например, его радиус, для квадрата и равностороннего треугольника — длина его стороны. Нам в каждый из классов необходимо гарантированно добавить методы, которые будут находить площадь (area) и периметр (perimeter) этих фигур. Вот тут то и могут пригодиться интерфейсы. Для этого после имени класса через двоеточие укажем имя интерфейса. Сделаем это и для других классов Square и Triangle.

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

Ошибка «ИнтерфейсФигур.Square» не содержит определения для «area» и не был найден метод расширения «area», принимающий тип «ИнтерфейсФигур.Square» в качестве первого аргумента.

В класс Prpogram добавим статический метод InfoFigure для контроля работы методов класса. Тогда код файла Program.cs будет следующим:

Результат совпадает с ранее рассмотренным примером(проверьте!).

Теперь немного теории.

Зачем нужны интерфейсы?

В языке С++ есть возможность множественного наследования. Разработчики C# решили отказаться от этого и придумали интерфейсы. Получается, что класс не может быть унаследован от нескольких классов, но при этом он может унаследовать несколько интерфейсов.

Часто бывает необходимо реализовать несколько классов, при этом у них будут одинаковые методы (по названию!), но они по-разному должны быть реализованы.

В терминах ООП .NET интерфейс это просто перечисление методов, которые должны быть обязательно реализованы у класса.

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

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

Свойства интерфейсов

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

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

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

Для реализации интерфейса в классе должны быть предоставлены тела (т.е. конкретные реализации) методов, описанных в этом интерфейсе. Каждому классу предоставляется полная свобода для определения деталей своей собственной реализации интерфейса. Следовательно, один и тот же интерфейс может быть реализован в двух классах по-разному. Тем не менее, в каждом из них должен поддерживаться один и тот же набор методов данного интерфейса. А в том коде, где известен такой интерфейс, могут использоваться объекты любого из этих двух классов, поскольку интерфейс для всех этих объектов остается одинаковым.

Благодаря поддержке интерфейсов в C# может быть в полной мере реализован главный принцип полиморфизма: один интерфейс — множество методов.

Объявление интерфейсов

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

где имя — это конкретное имя интерфейса. В объявлении методов интерфейса используются только их возвращаемый тип и сигнатура. Они, по существу, являются абстрактными методами.

Как пояснялось выше, в интерфейсе не может быть никакой реализации. Поэтому все методы интерфейса должны быть реализованы в каждом классе, включающем в себя этот интерфейс. В самом же интерфейсе методы неявно считаются открытыми, поэтому доступ (public) к ним не нужно указывать явно.

Помимо методов, в интерфейсах можно также указывать свойства, индексаторы и события. Интерфейсы не могут содержать член-данные (кроме событий?). В них нельзя также определить конструкторы, деструкторы или операторные методы. Кроме того, ни один из членов интерфейса не может быть объявлен как static.

Реализация интерфейсов

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

class имя_класса : имя_интерфейса< // тело класса>

где имя_интерфейса — это конкретное имя реализуемого интерфейса. Если уж интерфейс реализуется в классе, то это должно быть сделано полностью. В частности, реализовать интерфейс выборочно и только по частям нельзя.

В классе допускается реализовывать несколько интерфейсов. В этом случае все реализуемые в классе интерфейсы указываются списком через запятую.

В классе можно наследовать базовый класс и в тоже время реализовать один или более интерфейс. В таком случае имя базового класса должно быть указано перед списком интерфейсов, разделяемых запятой (см. пример выше).

Методы, реализующие интерфейс, должны быть объявлены как public. Дело в том, что в самом интерфейсе эти методы неявно подразумеваются как открытые, поэтому их реализация также должна быть открытой.

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

Наследование интерфейсов

Интерфейсы, как и классы, могут наследоваться:

При применении этого интерфейса класс BaseAction должен будет реализовать как методы и свойства интерфейса IRunAction, так и методы и свойства базового интерфейса IAction.

Однако в отличие от классов мы не можем применять к интерфейсам модификатор sealed (а также к методам интерфейсов), чтобы запретить наследование интерфейсов.

Также мы не можем применять к интерфейсам модификатор abstract, поскольку интерфейс фактически и так предоставляет абстрактный функционал, который должен быть реализован в классе.

Однако методы интерфейсов могут использовать ключевое слово new для сокрытия методов из базового интерфейса:

Здесь метод Move из IRunAction скрывает метод Move из базового интерфейса IAction. Большого смысла в этом нет, так как в данном случае нечего скрывать, то тем не менее мы так можем делать. А класс RunAction реализует метод Move сразу для обоих интерфейсов.

Модификаторы доступа интерфейсов

Как и классы, интерфейсы по умолчанию имеют уровень доступа internal, то есть такой интерфейс доступен только в рамках текущего проекта. Но с помощью модификатора public мы можем сделать интерфейс общедоступным:

Но при наследовании интерфейсов, как и при наследовании классов, следует учитывать, что производный интерфейс должен иметь тот же уровень доступа или более строгий, чем базовый интерфейс. Например:

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

Далее в примерах применение интерфейсов будет рассмотрено более подробно.

Интерфейс содержит определения для группы связанных функциональных возможностей, которые может реализовать неабстрактный класс или структура. An interface contains definitions for a group of related functionalities that a non-abstract class or a struct must implement.

С помощью интерфейсов можно, например, включить в класс поведение из нескольких источников. By using interfaces, you can, for example, include behavior from multiple sources in a class. Эта возможность очень важна в C#, поскольку этот язык не поддерживает множественное наследование классов. That capability is important in C# because the language doesn’t support multiple inheritance of classes. Кроме того, необходимо использовать интерфейс, если требуется имитировать наследование для структур, поскольку они не могут фактически наследовать от другой структуры или класса. In addition, you must use an interface if you want to simulate inheritance for structs, because they can’t actually inherit from another struct or class.

Интерфейс определяется с помощью ключевого слова interface, You define an interface by using the interface keyword. как показано в следующем примере. as the following example shows.

Имя структуры должно быть допустимым именем идентификатора C#. The name of the struct must be a valid C# identifier name. По соглашению имена интерфейсов начинаются с заглавной буквы I . By convention, interface names begin with a capital I .

Любой объект (класс или структура), реализующий интерфейс IEquatable , должен содержать определение для метода Equals, соответствующее сигнатуре, которую задает интерфейс. Any class or struct that implements the IEquatable interface must contain a definition for an Equals method that matches the signature that the interface specifies. В результате вы можете быть уверены, что класс, реализующий IEquatable , содержит метод Equals , с помощью которого экземпляр этого класса может определить, равен ли он другому экземпляру того же класса. As a result, you can count on a class that implements IEquatable to contain an Equals method with which an instance of the class can determine whether it’s equal to another instance of the same class.

Определение IEquatable не предоставляет реализацию для метода Equals . The definition of IEquatable doesn’t provide an implementation for Equals . Класс или структура может реализовывать несколько интерфейсов, но класс может наследовать только от одного класса. A class or struct can implement multiple interfaces, but a class can only inherit from a single class.

Дополнительные сведения об абстрактных классах см. в разделе Абстрактные и запечатанные классы и члены классов. For more information about abstract classes, see Abstract and Sealed Classes and Class Members.

Интерфейсы могут содержать методы, свойства, события, индексаторы, а также любое сочетание этих четырех типов членов. Interfaces can contain methods, properties, events, indexers, or any combination of those four member types. Ссылки на примеры см. в разделе Связанные разделы. For links to examples, see Related Sections. Интерфейс не может содержать константы, поля, операторы, конструкторы экземпляров, методы завершения или типы. An interface can’t contain constants, fields, operators, instance constructors, finalizers, or types. Члены интерфейса автоматически являются открытыми, и они не могут включать модификаторы доступа. Interface members are automatically public, and they can’t include any access modifiers. Члены также не могут быть статическими. Members also can’t be static.

Для реализации члена интерфейса соответствующий член реализующего класса должен быть открытым и не статическим, а также иметь такое же имя и сигнатуру, что и член интерфейса. To implement an interface member, the corresponding member of the implementing class must be public, non-static, and have the same name and signature as the interface member.

Если класс (или структура) реализует интерфейс, этот класс (или структура) должен предоставлять реализацию для всех членов, которые определяет этот интерфейс. When a class or struct implements an interface, the class or struct must provide an implementation for all of the members that the interface defines. Сам интерфейс не предоставляет функциональность, которую класс или структура может наследовать таким же образом, как можно наследовать функциональность базового класса. The interface itself provides no functionality that a class or struct can inherit in the way that it can inherit base class functionality. Однако если базовый класс реализует интерфейс, то любой класс, производный от базового класса, наследует эту реализацию. However, if a base class implements an interface, any class that’s derived from the base class inherits that implementation.

В следующем примере показана реализация интерфейса IEquatable . The following example shows an implementation of the IEquatable interface. Реализующий класс Car должен предоставлять реализацию метода Equals. The implementing class, Car , must provide an implementation of the Equals method.

Свойства и индексаторы класса могут определять дополнительные методы доступа для свойства или индексатора, определенного в интерфейсе. Properties and indexers of a class can define extra accessors for a property or indexer that’s defined in an interface. Например, интерфейс может объявлять свойство, имеющее акцессор get. For example, an interface might declare a property that has a get accessor. Класс, реализующий этот интерфейс, может объявлять это же свойство с обоими акцессорами ( get и set). The class that implements the interface can declare the same property with both a get and set accessor. Однако если свойство или индексатор использует явную реализацию, методы доступа должны совпадать. However, if the property or indexer uses explicit implementation, the accessors must match. Дополнительные сведения о явной реализации см. в статьях Явная реализация интерфейса и Свойства интерфейса. For more information about explicit implementation, see Explicit Interface Implementation and Interface Properties.

Интерфейсы могут наследовать от других интерфейсов. Interfaces can inherit from other interfaces. Класс может включать интерфейс несколько раз через наследуемые базовые классы или через интерфейсы, которые наследуются другими интерфейсами. A class might include an interface multiple times through base classes that it inherits or through interfaces that other interfaces inherit. Однако класс может предоставить реализацию интерфейса только однократно и только если класс объявляет интерфейс как часть определения класса ( class ClassName : InterfaceName ). However, the class can provide an implementation of an interface only one time and only if the class declares the interface as part of the definition of the class ( class ClassName : InterfaceName ). Если интерфейс наследуется, поскольку наследуется базовый класс, реализующий этот интерфейс, то базовый класс предоставляет реализацию членов этого интерфейса. If the interface is inherited because you inherited a base class that implements the interface, the base class provides the implementation of the members of the interface. Но производный класс может повторно реализовать любые члены виртуального интерфейса и не использовать наследованную реализацию. However, the derived class can reimplement any virtual interface members instead of using the inherited implementation.

Базовый класс также может реализовывать члены интерфейса с помощью виртуальных членов. A base class can also implement interface members by using virtual members. В таком случае производный класс может изменять поведение интерфейса путем переопределения виртуальных членов. In that case, a derived class can change the interface behavior by overriding the virtual members. Дополнительные сведения о виртуальных членах см. в статье Полиморфизм. For more information about virtual members, see Polymorphism.

Сводка по интерфейсам Interfaces summary

Интерфейс имеет следующие свойства. An interface has the following properties:

  • Интерфейс подобен абстрактному базовому классу, имеющему только абстрактные члены. An interface is like an abstract base class with only abstract members. Любой класс (или структура), реализующий интерфейс, должен реализовывать все его члены. Any class or struct that implements the interface must implement all its members.
  • Невозможно создать экземпляр интерфейса напрямую. An interface can’t be instantiated directly. Его члены реализуются любым классом (или структурой), реализующим интерфейс. Its members are implemented by any class or struct that implements the interface.
  • Интерфейсы могут содержать события, индексаторы, методы и свойства. Interfaces can contain events, indexers, methods, and properties.
  • Интерфейсы не содержат реализацию методов. Interfaces contain no implementation of methods.
  • Класс или структура может реализовывать несколько интерфейсов. A class or struct can implement multiple interfaces. Класс может наследовать базовому классу и также реализовывать один или несколько интерфейсов. A class can inherit a base class and also implement one or more interfaces.

Содержание раздела In this section

Явная реализация интерфейса Explicit Interface Implementation
В этом разделе объясняется, как создать член класса, который относится к интерфейсу. Explains how to create a class member that’s specific to an interface.

Практическое руководство. Явная реализация элементов интерфейса How to: Explicitly Implement Interface Members
В этом разделе содержится пример явной реализации членов интерфейсов. Provides an example of how to explicitly implement members of interfaces.

Практическое руководство. Явная реализация элементов двух интерфейсов How to: Explicitly Implement Members of Two Interfaces
В этом разделе содержится пример явной реализации членов интерфейсов с помощью наследования. Provides an example of how to explicitly implement members of interfaces with inheritance.

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

Нетрудно догадаться, что в библиотеках базовых классов .NET поставляются сотни предопределенных типов интерфейсов, которые реализуются в различных классах и структурах. Например, в состав ADO.NET входит множество поставщиков данных, которые позволяют взаимодействовать с определенной системой управления базами данных. Это означает, что в ADO.NET на выбор доступно множество объектов соединения (SqlConnection, OracleConnection, OdbcConnection и т.д.).

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

Для реализации интерфейса в классе должны быть предоставлены тела (т.е. конкретные реализации) методов, описанных в этом интерфейсе. Каждому классу предоставляется полная свобода для определения деталей своей собственной реализации интерфейса. Следовательно, один и тот же интерфейс может быть реализован в двух классах по-разному. Тем не менее в каждом из них должен поддерживаться один и тот же набор методов данного интерфейса. А в том коде, где известен такой интерфейс, могут использоваться объекты любого из этих двух классов, поскольку интерфейс для всех этих объектов остается одинаковым. Благодаря поддержке интерфейсов в C# может быть в полной мере реализован главный принцип полиморфизма: один интерфейс — множество методов.

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

где имя — это конкретное имя интерфейса. В объявлении методов интерфейса используются только их возвращаемый_тип и сигнатура. Они, по существу, являются абстрактными методами. Как пояснялось выше, в интерфейсе не может быть никакой реализации. Поэтому все методы интерфейса должны быть реализованы в каждом классе, включающем в себя этот интерфейс. В самом же интерфейсе методы неявно считаются открытыми, поэтому доступ к ним не нужно указывать явно.

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

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

где имя_интерфейса — это конкретное имя реализуемого интерфейса. Если уж интерфейс реализуется в классе, то это должно быть сделано полностью. В частности, реализовать интерфейс выборочно и только по частям нельзя.

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

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


[an error occurred while processing the directive]
Карта сайта