Interface
в C# — это языковая конструкция, похожая с точки зрения синтаксиса на class
, но фундаментально отличающаяся от него. Интерфейс можно сравнить с абстрактным классом, у которого только абстрактный метод, то есть нет никакой его реализации. У него есть функция множественного наследования (когда один класс наследуется сразу от нескольких).
Содержание статьи:
1. Вступление: знакомство с интерфейсами
2. Что определяет interface in C#?
3. Модификаторы доступа интерфейсов
4. Interface in C# и его применение
5. Interface implementation: как реализуются интерфейсы в C# по умолчанию
6. Множественная реализация интерфейсов
7. Интерфейсы в преобразованиях типов
Главная задача интерфейса — определить поведение, которое впоследствии будет реализовано в каком-то конкретном классе. У класса есть возможность поддерживать неограниченное количество интерфейсов, а значит и иметь множество поведений.
Поскольку в интерфейсах не заложена реализация, в них указывается только то, что необходимо сделать, но нет данных о том, как это сделать. Определяются свойства, функционал и методы без их реализации.
Давайте посмотрим на синтаксис:
public interface ITaxCalculator { int Calculate(); }
Так мы можем вызвать interface
вместо class
.
Обратите внимание на то, что для объектов интерфейсов в C# чаще всего используется вначале буква I, но это требование не обязательно.
Интерфейсы используются для создания приложений, компоненты которых не связаны между собой.
Важно: интерфейс не может содержать поля свойства, реализуемые автоматически.
Члены классов имеют свои модификаторы доступа. Они определяют контекст применения метода или использования переменной.
Уровень доступа интерфейсов по умолчанию internal
(только в рамках проекта). Чтобы сделать его общедоступным, применяется модификатор public
— доступен из любого места в коде и даже из других программ:
public interface IMovable { void Move(); }
Полная противоположность public
— модификатор private
. Это закрытый класс, который может быть доступен из кода в одном и том же классе/контексте. Предоставляет доступ с минимальными правами:
class Employee { private int i; double d; // private access by default }
Модификатор protected
доступен из любого места в классе, а также в производных классах из других сборок:
class A { protected int x = 123; } class B : A { static void Main() { var a = new A(); var b = new B(); // Error CS1540, because x can only be accessed by // classes derived from A. // a.x = 10; // OK, because this class derives from A. b.x = 10; } }
Сравнительная таблица модификаторов
Вызывающий объект | Internal | Public | Private | Protected |
В Class | да | да | да | да |
Производный класс — в одной сборке | да | да | нет | да |
Непроизводный класс — в одной сборке | да | да | нет | нет |
Производный класс — в другой сборке | нет | да | нет | да |
Непроизводный класс — в другой сборке | нет | да | нет | нет |
Существуют также такие модификаторы, как protected internal
и private protected
. Первый представляет собой сочетание сразу двух одноименных модификаторов. Доступен из одной сборки и производных классов. А второй — сочетает модификаторы private
/ protected
и доступен из любого места в текущем и производных классах одной сборки.
Объекты интерфейсов нельзя создать с помощью конструктора. Интерфейсы C# реализовываются в классах и структурах.
Например:
using System; namespace HelloApp { interface IMovable { void Move(); } class Person : IMovable { public void Move() { Console.WriteLine("Буря мглою"); } } struct Car : IMovable { public void Move() { Console.WriteLine("Небо кроет"); } } class Program { static void Action(IMovable movable) { movable.Move(); } static void Main(string[] args) { Person person = new Person(); Car car = new Car(); Action(person); Action(car); Console.Read(); } } }
В программе есть метод Action()
, а принятый им объект интерфейса — IMovable
. При написании кода ничего об объекте неизвестно, но мы знаем, что метод Move
будет им обязательно реализован. Поэтому мы можем вызвать этот метод.
Внимание! Если в свойствах и методах интерфейса отсутствуют модификаторы доступа, по умолчанию они являются public
.
Вывод программы в консоли:
Буря мглою Небо кроет
What is interface in С#? По сути, интерфейс — это залог того, что определенный тип обязательно реализует какой-то конкретный функционал.
Что мы знали раньше об интерфейсах?
public
и abstract
.Но начиная с версии C# 8.0 методы и свойства могут реализовываться в интерфейсах по умолчанию.
Допустим, что интерфейс в приложении реализуется классами. Чтобы добавить новый член, вам нужно обновить все классы для его поддержки или создать расширенный интерфейс с новым методом, который будет унаследован от предыдущего:
interface ICar { void GetSpeed(); void GetMileage(); } interface IInternetCar : ICar { void SendCommand(); }
Но чем больше методов и функций в расширенном интерфейсе, тем все быстрее он становится неуправляемым. Эту проблему решают интерфейсы, реализуемые по умолчанию.
Они полезны при добавлении новых членов, не нарушая существующую реализацию:
interface ICar { void GetSpeed(); void GetMileage(); public void SendCommand() { //Send the Command. } }
С interface implementation в C# нет никакой необходимости в применении новых интерфейсов и изменениях в существующей реализации.
Классы могут переопределить реализацию по умолчанию.
Например, если класс MorrisGarage
реализует метод SendCommand
, будет вызвана его реализация:
public class MorrisGarage : ICar { public void GetMileage() { Console.WriteLine("10 KM Per Liter"); } public void GetSpeed() { Console.WriteLine("200 KMPH"); } public void SendCommand() { Console.WriteLine("Command Sent via Morris Garage Class"); } }
Интерфейсы в C# могут:
private
-члены:public interface ICar { private void Initialize() { //Initialize the Command Center } void GetSpeed(); void GetMileage(); public void SendCommand() { Initialize(); Console.WriteLine("Command Sent via Interface"); } }
public interface ICar { private static string commandName = "LOCK_CAR"; private void Initialize(string cName) { commandName = cName; //Initialize the Command Center } void GetSpeed(); void GetMileage(); public void SendCommand(string cName) { Initialize(cName); Console.WriteLine("Command Sent via Interface"); } }
protected
-члены, которые доступны в производном интерфейсе, но не в производном классе:public interface ICar { public void SendCommand() { Console.WriteLine("Command Sent via Interface"); } protected void SendCriticalCommand() { Console.WriteLine("Critical Command Sent via Interface"); } } public interface IAnotherCar : ICar { public void Send(bool bCritical) { if (bCritical) this.SendCriticalCommand(); else
virtual
-члены (без возможности переопределения метода классом):public interface ICar { public virtual void SendCommand() { Console.WriteLine("Command Sent via Interface"); } } public interface IAnotherCar :ICar { void ICar.SendCommand() { Console.WriteLine("Command Sent via another Interface"); } } class MorrisGarage: ICar, IAnotherCar { } class Program { static void Main() { ICar mg= new MorrisGarage(); mg.SendCommand(); //Calls the virtual implementation. IAnotherCar mgOverridden = new MorrisGarage(); mgOverridden.SendCommand(); //Calls the overridden implementation. } }
Реализация интерфейсов по умолчанию (interface implementation в С#) позволяет разработчикам не нарушать существующую реализацию, но при этом вносить новые изменения.
В C# нет поддержки множественного наследования — унаследовать класс можно только от одного класса. Благодаря тому, что в C# класс может реализовать сразу несколько интерфейсов (implement interface в C#), ограничение с невозможностью множественного наследования можно обойти.
Все интерфейсы в class
обычно указываются через запятую.
Например:
using System; namespace HelloApp { interface IAccount { int CurrentSum { get; } // Текущая сумма на счету void Put(int sum); // Положить деньги на счет void Withdraw(int sum); // Взять со счета } interface IClient { string Name { get; set; } } class Client : IAccount, IClient { int _sum; // Переменная для хранения суммы public string Name { get; set; } public Client(string name, int sum) { Name = name; _sum = sum; } public int CurrentSum { get { return _sum; } } public void Put(int sum) { _sum += sum; } public void Withdraw(int sum) { if (_sum >= sum) { _sum -= sum; } } } class Program { static void Main(string[] args) { Client client = new Client("Tom", 200); client.Put(30); Console.WriteLine(client.CurrentSum); //230 client.Withdraw(100); Console.WriteLine(client.CurrentSum); //130 Console.Read(); } } }
Здесь реализованы интерфейсы IAccount
(определяет свойство CurrentSum
и методы Put
— поступление суммы на счет, Withdraw
— изъятие суммы) и IClient
(определяет свойство Name
).
Client class
реализует оба интерфейса, после чего применяется в программе.
Как видно из примера в разделе «Множественная реализация интерфейсов», IAccount
-интерфейс реализуется классом Client
. Ссылка на объект Client
может храниться в переменной IAccount
:
// Все объекты Client являются объектами IAccount IAccount account = new Client("Том", 200); account.Put(200); Console.WriteLine(account.CurrentSum); // 400 // Не все объекты IAccount являются объектами Client, необходимо явное приведение Client client = (Client)account; // IAccount интерфейс не имеет свойства Name, необходимо явное приведение string clientName = ((Client)account).Name;
Преобразование от класса к интерфейсу выполняется автоматически и аналогично преобразованию от производного типа к базовому классу, поскольку любой объект Client
может реализовать IAccount
-интерфейс.
Преобразование от интерфейса к классу идентично превращению базового типа в производный, поскольку не каждый объект IAccount
является объектом Client
. Здесь нужна операция преобразования типов.
Интерфейс определяет методы, реализуемые в классе, который в C# наследует этот generic interface.
Интерфейсы используются для того, чтобы направить классы на реализацию методов: событий, индексаторов, свойств. В interface в C# описываются функциональные возможности, но без их реализации (он определяет только спецификацию).
Интерфейс — альтернатива множественному наследованию.
Interface в C# обладает такими особенностями:
public
;Интерфейс может быть реализован в любом количестве классов, а в одном классе может быть реализовано любое количество интерфейсов.
Для объявления интерфейса нужно применить ключевое слово interface
.
Интерфейсы могут наследовать другие интерфейсы. Синтаксис такого наследования такой же, как синтаксис наследования классов. Например:
interface Name : name_interface1, name_interface2, ..., name_interfaceN { // указываются события, свойства, методы, индексаторы интерфейса ... }
где:
Name
— имя интерфейса, который наследует другие интерфейсы;name_interface1, name_interface2, ..., name_interfaceN
— интерфейсы-предки (все они указываются через запятую).Interface в C# лучше всего использовать в случаях, когда все понятия нужно описать с точки зрения их функционального назначения, они пригодятся, когда не нужны детали реализации свойств и методов.
Видео: интерфейсы в C#: зачем нужны и как используются
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…
Дедлайн (от англ. deadline — «крайний срок») — это конечная дата стачи проекта или задачи…