Г. Шилдт - Полный справочник по C# (1160789), страница 60
Текст из файла (страница 60)
И в этом нет ничегоудивительного, поскольку каждый класс волен решить эту задачу так, как "считает"нужным.324Часть I. Язык С#Использование интерфейсных ссылокВозможно, вы будете несколько удивлены, узнав, что можно объявить ссылочнуюпеременную интерфейсного типа. Другими словами, можно создать переменнуюссылку на интерфейс. Такая переменная может ссылаться на любой объект, которыйреализует ее интерфейс. При вызове метода для объекта посредством интерфейснойссылки будет выполнена та версия указанного метода, которая реализована этим объектом. Этот процесс аналогичен использованию ссылки на базовый класс для доступак объекту производного класса (см. главу 11).Использование интерфейсной ссылки демонстрируется в следующем примере.Здесь используется одна и та же интерфейсная переменная-ссылка, чтобы вызыватьметоды для объектов как класса ByTwos, так и класса Primes.// Демонстрация использования интерфейсных ссылок.using System;// Определение интерфейса,public interface ISeries {int getNextO; // Возвращает следующее число ряда.void reset(); // Выполняет перезапуск.void setStart(int x ) ; // Устанавливает начальное// значение.}// Используем интерфейс ISeries для генерирования// последовательности четных чисел,class ByTwos : ISeries {int start;int val;public ByTwos() {start = 0;val = 0;}public int getNext() {val += 2;return val;}public void reset() {val = start;}public void setStart(int x) {start = x;val = start;-^// Используем интерфейс ISeries для построения// ряда простых чисел,class Primes : ISeries {int start;int val;Глава 12.
Интерфейсы, структуры и перечисления325public Primes () {start = 2;val = 2;public int getNext()int i, j;bool isprime;for(i « val; i < 1000000;isprime = true;for(j = 2; j < (i/j + 1 ) ;if((i%j)==0) {isprime = falserbreak;if(isprime) {val = i;break;return val;public void reset() {val = start;public void setStart(int x) {start = x;val = start;class SeriesDemo2 {public static void Main() {ByTwos twoOb = new ByTwos();Primes primeOb = new Primes(ISeries ob;for(int i=0; i < 5;ob = twoOb;Console.WriteLine("Следующее четное число равно " +ob.getNext ());ob = primeOb;Console.WriteLine("Следующее простое число равно " +ob.getNext() ) ;Вот результаты выполнения этой программы:Следующее четное число равно 2Следующее простое число равно 3Следующее четное число равно 4Следующее простое число равно 5326Часть I. Язык С#СледующееСледующееСледующееСледующееСледующееСледующеечетное число равно бпростое число равно 7четное число равно 8простое число равно 11четное число равно 10простое число равно 13В методе Main() объявляется переменная ob как ссылка на интерфейс I S e r i e s .Это означает, что ее можно использовать для хранения ссылок на любой объект, который реализует интерфейс I S e r i e s .
В данном случае она служит для ссылки на объекты twoOb и primeOb, которые являются экземплярами классов ByTwos и Primes,соответственно, причем оба класса реализуют один и тот же интерфейс, I S e r i e s .Важно понимать, что интерфейсная ссылочная переменная "осведомлена" толькоо методах, объявленных "под сенью" ключевого слова i n t e r f a c e . Следовательно, интерфейсную ссылочную переменную нельзя использовать для доступа к другим переменным или методам, которые может определить объект, реализующий этот интерфейс.Интерфейсные свойстваКак и методы, свойства определяются в интерфейсе без тела.
Ниже приведен формат спецификации свойства.// Интерфейсное свойствотип имя{get;set;Свойства, предназначенные только для чтения или только для записи, содержаттолько get- или set-элемент, соответственно.Рассмотрим еще одну версию интерфейса ISeries и класса ByTwos, в котором дляполучения следующего элемента ряда и его установки используется свойство.// Использование свойства в интерфейсе.using System;public interface ISeries {// Интерфейсное свойство,int next {get; // Возвращает следующее число ряда.s e t ; // Устанавливает следующее число ряда.// Реализация интерфейса ISeries,class ByTwos : ISeries {m t val;public ByTwos() {val = 0;}// Получаем или устанавливаем значение ряда,public int next {get {Глава 12.
Интерфейсы, структуры и перечисления327val += 2;return val;}set {val = value;// Демонстрируем использование интерфейсного свойства,class SeriesDemo3 {public s t a t i c void Main() {ByTwos ob = new ByTwos();// Получаем доступ к ряду через свойство.for(int i=0; i < 5; i++)Console.WriteLine("Следующее значение равно " +ob.next);Console.WriteLine("ХпНачинаем с числа 21");ob.next = 2 1 ;for(int i=0; i < 5; i++)Console.WriteLine("Следующее значение равно " +ob.next);Результаты выполнения этой программы таковы:Следующее значение равно 2Следующее значение равно 4Следующее значение равно бСледующее значение равно 8Следующее значение равно 10Начинаем с числа 21Следующее значение равноСледующее значение равноСледующее значение равноСледующее значение равноСледующее значение равно2325272931So Интерфейсные индексаторыВ интерфейсе можно определить и индексатор.
Объявление индексатора в интерфейсе имеет следующий формат записи:// Интерфейсный индексатортип_элемента t h i s [ i n t индекс]{get;set;}Индексаторы, предназначенные только для чтения или только для записи, содержат только get- или set-метод, соответственно.Предлагаем еще одну версию интерфейса ISeries, в который добавлен индексатор, предназначенный только для чтения элемента ряда.328Часть I.
Язык С#// Добавление в интерфейс индексатора,using System;public interface ISeries {// Интерфейсное свойство,int next {get; // Возвращает следующее число ряда.set; // Устанавливает следующее число ряда.// Интерфейсный индексатор,int this[int index] {get; // Возвращает заданный член ряда.// Реализация интерфейса ISeries,class ByTwos : ISeries {int val;public ByTwos() {val = 0;// Получаем или устанавливаем значение с помощью// свойства,public int next {get {val += 2;return val;}set {val = value;// Получаем значение с помощью индексатора,public int this[int index] {get {val = 0;for(int i=0; i<index;val += 2;return val;// Демонстрируем использование интерфейсного индексатора,class SeriesDemo4 {public static void Main() {ByTwos ob = new ByTwos();// Получаем доступ к ряду посредством свойства,for(int i=0; i < 5; i++)Console.WriteLine("Следующее значение равно " +ob.next);Глава 12.
Интерфейсы, структуры и перечисления329Console.WriteLine("ХпНачинаем с числа 21");ob.next = 2 1 ;for(int i=0; i < 5; i++)Console.WriteLine("Следующее значение равно " +ob.next);Console.WriteLine("ХпПереход в исходное состояние.");ob.next = 0;// Получаем доступ к ряду посредством индексатора.for(int i=0; i < 5; i++)Console.WriteLine("Следующее значение равно " +Вот результаты, сгенерированные этой программой:Следующее значение равно 2Следующее значение равно 4Следующее значение равно бСледующее значение равно 8Следующее значение равно 10Начинаем с числа 21Следующее значение равноСледующее значение равноСледующее значение равноСледующее значение равноСледующее значение равноПереход вСледующееСледующееСледующееСледующееСледующееисходноезначениезначениезначениезначениезначение2325272931состояние.равно 0равно 2равно 4равно бравно 8Наследование интерфейсовОдин интерфейс может унаследовать "богатство" другого.
Синтаксис этого механизма аналогичен синтаксису, используемому для наследования классов. Если классреализует интерфейс, который наследует другой интерфейс, этот класс должен обеспечить способы реализации для всех членов, определенных внутри цепочки наследования интерфейсов. Рассмотрим такой пример:// Один интерфейс может наследовать другой.using System;public interface A {void methl () ;void meth2();}// Интерфейс В теперь включает методы methl()/ / а также добавляет метод m e t h 3 ( ) .330и meth2(),Часть I.
Язык С#public interface В : A {void meth3();// Этот класс должен реализовать все методы// интерфейсов А и В.class MyClass : В {public void methl() {Console. WriteLine ("Реализация метода methl(). ff );public void meth2() {Console.WriteLine("Реализация метода meth2().");public void xneth3() {Console.WriteLine("Реализация метода meth3().");class IFExtend {public static void Main() { yMyClass ob = new MyClass();ob.methl();ob.meth2();ob.meth3();Если бы в качестве эксперимента вы попытались удалить метод methl (), реализованный в классе MyClass, то сразу же получили бы от компилятора сообщение обошибке.
Как упоминалось выше, любой класс, который реализует интерфейс, долженреализовать все методы, определенные этим интерфейсом, включая методы, которыеунаследованы от других интерфейсов.Сокрытие имен с помощью наследованияинтерфейсовВ производном интерфейсе можно объявить член, который скрывает член, определенный в базовом интерфейсе. Это происходит при совпадении их сигнатур. Такоесовпадение вызовет предупреждающее сообщение, если член производного интерфейса не модифицировать с помощью ключевого слова new.Явная реализация членов интерфейсаПри реализации члена интерфейса можно квалифицировать его имя с использованием имени интерфейса.