Интерфейсы
- 1. Назначение интерфейсов. Особенности применения интерфейсов в C#
- 2. Какое отличие между интерфейсами и абстрактными классами?
- 3. Сколько классов могут иметь реализацию методов интерфейса?
- 4. Сколько интерфейсов может быть реализовано в одном классе?
- 5. Какой общий вид описания интерфейса?
- 6. Какие элементы языка программирования можно указывать в интерфейсах?
- 7. Как выглядит общая форма реализации интерфейса в классе?
- 8. Какая общая форма класса реализующего несколько интерфейсов?
- 9. Пример объявления интерфейса и класса наследующего этот интерфейс
- 10. Пример объявления двух интерфейсов и класса, который реализует методы этих интерфейсов
- 11. Пример использования ссылки на интерфейс для доступа к методам класса
- 12. Каким образом в интерфейсе описывается свойство?
- 13. Пример интерфейса, в котором описывается индексатор
- 14. Какие элементы программирования языка C# нельзя описывать в интерфейсах?
- 15. Как работает механизм наследования интерфейсов?
- 16. Что такое явная реализация члена интерфейса?
- 17. Когда целесообразно применять явную реализацию члена интерфейса? Примеры
- 18. В каких случаях лучше использовать интерфейс, а в каких абстрактный класс?
- Связанные темы
Поиск на других ресурсах:
1. Назначение интерфейсов. Особенности применения интерфейсов в C#
Интерфейс определяет ряд методов (свойств, индексаторов, событий), которые должны быть реализованы в классе, который наследует (реализует) данный интерфейс. Интерфейсы используются для того, чтобы указать классам, что именно нужно реализовать в этих классах. Реализовывать нужно методы (свойства, индексаторы, события). Таким образом, интерфейс описывает функциональные возможности без конкретной реализации. Иными словами интерфейс определяет спецификацию но не реализацию.
Использование интерфейсов есть эффективным в случаях, когда нужно создать альтернативу множественного наследования. Любой класс может унаследовать несколько интерфейсов. При этом все методы унаследованных интерфейсов должны быть реализованы в классе.
Структура также как и класс может реализовывать любое количество интерфейсов.
Особенности интерфейсов
- в интерфейсе нельзя вписывать реализацию его элементов;
- невозможно создать экземпляр интерфейса;
- можно создать ссылку на интерфейс;
- в интерфейсе не может быть конструкторов;
- интерфейс не может содержать поля;
- в интерфейсе не может быть осуществлена перегрузка операторов;
- все методы интерфейса по умолчанию объявлены как public.
При использовании интерфейсов в классах-наследниках:
- запрещено изменять модификатор доступа для метода при его реализации;
- невозможно объявить методы интерфейса как virtual;
- запрещено объявлять методы интерфейса с ключевым словом static (как статические).
⇑
2. Какое отличие между интерфейсами и абстрактными классами?
В языке программирования C# существуют следующие отличия между интерфейсами и абстрактными классами:
- В интерфейсе запрещено прописывать реализацию его членов. В абстрактном классе часть членов может иметь реализацию. Иными словами, интерфейс это тот же абстрактный класс, у которого все методы абстрактные.
- В интерфейсе запрещено описывать поля (переменные, объекты), в абстрактном классе можно.
- В интерфейсе запрещено объявление перегруженных операторов. В абстрактном классе при соблюдении некоторых условий допускается объявление перегруженных операторов.
- Интерфейс не может содержать конструктор. В абстрактном классе может быть объявлен конструктор.
- Любой класс может быть унаследован от нескольких интерфейсов. При этом любой класс может быть унаследован только от одного абстрактного класса (и не более).
- В интерфейсе запрещено объявлять статические элементы (с ключевым словом static). В абстрактном классе допускается объявление статических элементов.
- В интерфейсе все элементы считаются как public, и поэтому модификаторы доступа в интерфейсе не используются. В абстрактном классе элементы могут быть объявлены с любым модификатором доступа (private, protected, public).
⇑
3. Сколько классов могут иметь реализацию методов интерфейса?
Если интерфейс определен, то он может быть реализован в любом количестве классов.
⇑
4. Сколько интерфейсов может быть реализовано в одном классе?
В одном классе может быть реализовано любое количество интерфейсов.
⇑
5. Какой общий вид описания интерфейса?
Интерфейсы объявляются с помощью ключевого слова interface. Общая форма описания интерфейса, в котором определяются методы, следующая:
interface имя { возвращаемый_тип1 имя_метода1(параметры1); возвращаемый_тип2 имя_метода2(параметры2); // ... возвращаемый_типN имя_методаN(параметрыN); }
где
- имя – конкретное имя интерфейса;
- имя_метода1, имя_метода2, …, имя_методаN – имена методов интерфейсов;
- возвращаемый_тип1, возвращаемый_тип2, …, возвращаемый_типN – типы, которые возвращаются методами интерфейса;
- параметры1, параметры2, …, параметрыN – списки параметров методов интерфейса.
Кроме методов, в интерфейсах можно указывать свойства, события и индексаторы.
⇑
6. Какие элементы языка программирования можно указывать в интерфейсах?
В интерфейсах можно указывать:
- методы;
- свойства;
- индексаторы;
- события.
⇑
7. Как выглядит общая форма реализации интерфейса в классе?
Общая форма реализации интерфейса в классе имеет следующий вид:
class имя_класса : имя_интерфейса { // тело класса ... }
где имя_интерфейса – имя интерфейса, методы (свойства, индексаторы, события) которого реализуются в классе. Класс обязательно должен реализовать все методы интерфейса.
⇑
8. Какая общая форма класса реализующего несколько интерфейсов?
Класс может реализовать несколько интерфейсов. В этом случае все интерфейсы определяются списком через запятую.
Общая форма класса реализующего несколько интерфейсов:
class имя_класса : имя_интерфейса1, имя_интерфейса2, ..., имя_интерфейсаN { // тело класса ... }
где имя_интерфейса1, имя_интерфейса2, …, имя_интерфейсаN – имена интерфейсов, которые должен реализовать класс. Класс должен реализовать все методы всех интерфейсов.
⇑
9. Пример объявления интерфейса и класса наследующего этот интерфейс
В данном примере интерфейсу присваивается имя IMyInterface. Рекомендовано к имени интерфейса добавить префикс ‘I’ в соответствии с общераспространенной практикой.
Интерфейс объявлен как public.
public interface IMyInterface { int MyGetInt(); // метод, возвращающий число типа int double MyGetPi(); // метод, возвращающий число Pi int MySquare(int x); // метод, возвращающий x в квадрате double MySqrt(double x); // метод возвращающий корень квадратный из x }
В данном примере, в интерфейсе объявлено описание четырех методов, которые должны быть реализованы во всех классах, определяющих эти интерфейсы. Это методы: MyGetInt(), MyGetPi(), MySquare(), MySqrt().
Пример описания класса использующего этот интерфейс.
public class MyClass : IMyInterface { // модификатор доступа public public int MyGetInt() { return 25; } public double MyGetPi() { return Math.PI; } public int MySquare(int x) { return (int)(x * x); } public double MySqrt(double x) { return (double)Math.Sqrt(x); } }
Все методы, которые определяются в классе, должны иметь тип доступа public. Если установить другой тип доступа (private или protected), то Visual Studio выдаст следующее сообщение:
"MyClass does not implement interface member MyFun() because it is not public."
где MyFun() – название функции, которая реализована в классе с модификатором доступа private или protected.
Это связано с тем, что в самом интерфейсе эти методы неявно считаются открытыми (public). Поэтому их реализация должна быть открытой.
⇑
10. Пример объявления двух интерфейсов и класса, который реализует методы этих интерфейсов
В нижеследующем примере объявлено два интерфейса с именами MyInterface и MyInterface2. Первый интерфейс содержит 4 методы. Второй интерфейс содержит 1 метод.
Также объявлен класс MyClass, использующий эти два интерфейса. Класс обязательно должен реализовать все методы обоих интерфейсов, то есть в сумме 5 методов.
public interface IMyInterface { int MyGetInt(); // метод, возвращающий число типа int double MyGetPi(); // метод, возвращающий число Pi int MySquare(int x); // метод, возвращающий x в квадрате double MySqrt(double x); // метод, возвращающий корень квадратный из x } public interface IMyInterface2 { double MySqrt2(double x); // корень квадратный из x } public class MyClass : IMyInterface, IMyInterface2 { // методы из интерфейса MyInterface public int MyGetInt() { return 25; } public double MyGetPi() { return Math.PI; } public int MySquare(int x) { return (int)(x * x); } public double MySqrt(double x) { return (double)Math.Sqrt(x); } // метод из интерфейса MyInterface2 public double MySqrt2(double x) { return (double)Math.Sqrt(x); } }
⇑
11. Пример использования ссылки на интерфейс для доступа к методам класса
В C# допускается описывать ссылки на интерфейс. Если описать переменную-ссылку на интерфейс, то с ее помощью можно вызвать методы класса, который использует этот интерфейс.
Пример.
public interface IMyInterface { double MyGetPi(); // метод, возвращающий число Pi } class MyClass : IMyInterface { // методы из интерфейса MyInterface public double MyGetPi() { return Math.PI; } } // вызов из программного кода private void button1_Click(object sender, EventArgs e) { MyClass mc = new MyClass(); // создание объекта класса mc IMyInterface mi; // ссылка на интерфейс double d; mi = mc; // mi ссылается на объект класса mc d = mi.MyGetPi(); // d = 3.14159265358979 label1.Text = d.ToString(); }
В данном примере создается объект (экземпляр) класса MyClass с именем mc. Затем описывается ссылка на интерфейс IMyInterface с именем mi.
Строка
mi=mc;
приводит к тому, что ссылка mi указывает на объект класса mc. Таким образом, через ссылку mi можно иметь доступ к методам класса MyClass, так как класс MyClass реализует методы интерфейса IMyInterface.
С помощью ссылки на интерфейс можно иметь доступ к методам классов, которые реализуют описанные в этом интерфейсе методы.
⇑
12. Каким образом в интерфейсе описывается свойство?
Свойство описывается в интерфейсе без тела. Общая форма объявления интерфейсного свойства следующая:
тип имя_свойства { get; set; }
Если свойство предназначено только для чтения, то используется один только аксессор get.
Если свойство предназначено для записи, то используется только один аксессор set.
Пример. Описывается интерфейс и класс. Класс возвращает свойство MyPi.
public interface IMyInterface { double MyGetPi(); // метод, возвращающий число Pi // свойство, возвращающее число Pi double MyPi { get; } } class MyClass : IMyInterface { // метод public double MyGetPi() { return Math.PI; } // реализация свойства в классе public double MyPi { get { return Math.PI; } } } // использование интерфейсного свойства в обработчике события клика на кнопке private void button1_Click(object sender, EventArgs e) { MyClass mc = new MyClass(); // создание объекта класса mc label1.Text = mc.MyPi.ToString(); // чтение свойства }
⇑
13. Пример интерфейса, в котором описывается индексатор.
Общая форма объявления интерфейсного индексатора имеет вид:
тип this[int индекс] { get; set; }
Пример описания и использования интерфейсного индексатора, который считывает элемент из массива, состоящего из 5 элементов типа double.
public interface IMyInterface { // интерфейсный индексатор double this[int index] { get; } } class MyClass : IMyInterface { double[] mas = { 3, 2.9, 0.5, 7, 8.3 }; public double this[int index] { get { return mas[index]; } } } private void button1_Click(object sender, EventArgs e) { MyClass mc = new MyClass(); // создание объекта класса mc double d; d = mc[2]; // d = 0.5 label1.Text = d.ToString(); }
⇑
14. Какие элементы программирования языка C# нельзя описывать в интерфейсах?
Интерфейсы не могут содержать:
- члены данных;
- конструкторы;
- деструкторы;
- операторные методы.
⇑
15. Как работает механизм наследования интерфейсов?
Интерфейс может наследовать другой интерфейс. Синтаксис наследования интерфейсов такой же, как и у классов.
Общая форма наследования интерфейса следующая:
interface имя_интерфейса : имя_интерфейса1, имя_интерфейса2, ..., имя_интерфейсаN { // методы, свойства, индексаторы и события интерфейса ... }
где имя_интерфейса – имя интерфейса, который наследует другие интерфейсы;
имя_интерфейса1, имя_интерфейса2, …, имя_интерфейсаN – имена интерфейсов-предков.
Пример. В данном примере класс MyClass использует интерфейс, который наследует другой интерфейс. В классе нужно реализовать все методы (свойства, индексаторы, события) интерфейса MyInterface1 и интерфейса MyInterface2.
// базовый интерфейс interface MyInterface1 { void Int1_Meth(); } // интерфейс, который наследует другой интерфейс interface MyInterface2 : MyInterface1 { void Int2_Meth(); } // класс, который использует интерфейс MyInterface2 class MyClass : MyInterface2 { // реализация метода интерфейса MyInterface1 public void Int1_Meth() { // тело метода // ... return; } // реализация метода интерфейса MyInterface2 public void Int2_Meth() { // тело метода // ... return; } }
⇑
16. Что такое явная реализация члена интерфейса?
Если перед именем метода (свойства, индексатора, события) стоит имя интерфейса через разделитель ‘ . ‘ (точка), то это называется явной реализацией члена интерфейса.
Пример явной реализации.
// базовый интерфейс interface MyInterface1 { void Method(); } // класс, который реализует интерфейс MyInterface1 class MyClass : MyInterface1 { // явная реализация метода интерфейса MyInterface1 void MyInterface1.Method() // указывается имя интерфейса { // тело метода // ... return; } }
⇑
17. Когда целесообразно применять явную реализацию члена интерфейса? Примеры.
Явная реализация члена интерфейса применяется в следующих случаях:
- когда нужно, чтобы интерфейсный метод был доступен по интерфейсной ссылке, а не по объекту класса, реализующего данный интерфейс. В этом случае интерфейсный метод не является открытым (public) членом класса (см. пример 1);
- когда в одном классе реализованы два интерфейса, в которых методы имеют одинаковые имена и сигнатуру (см. пример 2).
Пример 1. Явная реализация интерфейсного метода. По интерфейсной ссылке метод есть доступен, а по объекту класса недоступен.
// Интерфейс interface MyInterface1 { void Method(); } // класс, вызывающий интерфейс class MyClass : MyInterface1 { // явная реализация метода интерфейса MyInterface1 // модификатор доступа, должен отсутствовать void MyInterface1.Method() // указывается имя интерфейса { // тело метода // ... return; } void InternalMethod() { MyInterface1 mi = this; // mi - интерфейсная ссылка mi.Method(); // работает! MyClass mc = this; // mc - объект класса MyClass // mc.Method() - невозможно вызвать - метод не открыт для объекта } }
Пример 2. Есть два интерфейса MyInterface1 и MyInterface2. Каждый из них имеет методы с одинаковыми именами и сигнатурами. В данном случае это метод Method(), не возвращающий параметров (void). С помощью явной реализации класс распознает эти методы.
// интерфейс 1 interface MyInterface1 { void Method(); } // интерфейс 2 interface MyInterface2 { void Method(); } // класс, который использует два интерфейса class MyClass : MyInterface1, MyInterface2 { // явная реализация - модификатор доступа (public) должен отсутствовать // метод из интерфейса MyInterface1 void MyInterface1.Method() { // тело метода // ... return; } // метод из интерфейса MyInterface2 void MyInterface2.Method() { // тело метода // ... return; } }
⇑
18. В каких случаях лучше использовать интерфейс, а в каких абстрактный класс?
Интерфейс целесообразно использовать в случаях, если некоторые понятия должны быть описаны с точки зрения функционального назначения, без уточнения деталей реализации.
Абстрактный класс целесообразно использовать тогда, когда все же нужно уточнять некоторые детали реализации.