Главная страница Библиотека (скачать книги) Скачать софт Введение в программирование Стандарты для C++ Уроки по C# Уроки по Python HTML Веб-дизайн Ассемблер в среде Windows ActiveX Javascript Общее о Линукс Линукс - подробно Линукс - новое Delphi Паскаль для начинающих Турбопаскаль Новости Партнеры Наши предложения Архив новостей |
Интерфейсы.Итак, еще одно кажущееся таким знакомым слово. Его часто можно встретить в повседневной компьютерной жизни и, где бы оно ни встретилось, толкования этого слова могут несколько отличаться друг от друга. Проясним его значение в контексте языка C#. Прежде всего введем понятие контракта. Контракт - это набор четко определенных условий, которые регулируют отношения между классом-сервером и его клиентами; включает индивидуальные контракты для всех экспортируемых членов класса и глобальные свойства класса. Интерфейс определяет контракт, а классы и структуры, реализующие данный интерфейс, должны четко придерживаться данного контракта. Другими словами интерфейс - это набор описаний методов и свойств, которые реализующий интерфейс класс или структура (класс иди структура наследуют данный интерфейс) обязаны определить. Таким образом, интерфейс напоминает абстрактный класс, у которого все методы абстрактны. Использование интерфейсов - удобный способ разделения функциональных возможностей. Сначала определяются интерфейсы, а затем разрабатываются классы, реализующие данные интерфейсы. Методы класса могут быть сгруппированы в разных интерфейсах. Основной задачей интерфейса является определение контракта, не зависящего от реализации. Каждый интерфейс имеет набор методов, не реализованных непосредственно. Для каждого метода определена сигнатура, описывающая количество и тип аргументов, а также тип возвращаемого методом значения. Пример интерфейса, описывающего методы для масштабирования объекта. interface IScalable { void ScaleX(double sx); void ScaleY(double sy); } Правила описания интерфейсовИнтерфейсы могут быть объявлены с любым из четырех модификаторов доступа, описанных ранее (при условии их вложенности в другие элементы), но все элементы интерфейсов должны быть общедоступны (по умолчанию). Интерфейсы могут быть членами пространств имен, классов или структур, и могут содержать описания следующих элементов:
Последние три элемента будут рассмотрены в последующих уроках. ******* Интерфейсы и наследованиеВам уже известно, что в языке C# разрешено только простое наследование (наследуется только один класс). В случае с интерфейсами разрешено и простое и множественное наследование. interface IA { void f(); } interface IB { void g(); } class C : IA, IB { // обязательная реализация функций f и g public void f() { ... } public void g() { ... } } В случае, если класс наследует некий базовый класс и реализует один или несколько интерфейсов, в линии наследования класс ставится на первое место. interface IA { void f(); } interface IB { void g(); } class Base { ... } class C : Base, IA, IB { // обязательная реализация функций f и g public void f() { ... } public void g() { ... } } При преобразовании объекта к интерфейсу в иерархии наследования ищется класс, у которого в списке базовых классов указан этот интерфейс. Одного наличия правильных функций недостаточно. interface IF { void F(); } class T : IF { public void F() { Console.WriteLine("T"); } public T() { F(); } } class TDerived : T { public new void F() { Console.WriteLine("TDerived"); } public TDerived() { F(); } } class Test { static void Main() { T td = new TDerived(); // Преобразование объекта к интерфейсу IF iif = (IF)td; iif.F(); } } Вывод на экран: T TDerived T
Проведем анализ кода и результата. Сначала создается ссылка типа базового класса T, а затем выделяется память под объект производного класса TDerived, соответственно, вызываются конструктор базового и производных классов (на экране T и TDerived). interface IF { void F(); } class T : IF { public void F() { Console.WriteLine("T"); } public T() { F(); } } class TDerived : T, IF { public new void F() { Console.WriteLine("TDerived"); } public TDerived() { F(); } } class Test { static void Main() { T td = new TDerived(); // Преобразование объекта к интерфейсу IF iif = (IF)td; iif.F(); } } Вывод на экран: T TDerived TDerived******* Если некоторый интерфейс реализуется классом, возможно неявное преобразование ссылки на экземпляр класса в ссылку на интерфейс. Такое преобразование относится к неявным, поскольку на этапе компиляции заведомо известно, что оно пройдет успешно. ******* class Test { static void Main() { T td = new TDerived(); // Неявное преобразование объекта к интерфейсу IF iif = td; iif.F(); } } Оператор isПерепишем предыдущий пример следующим образом: interface IF { void F(); } class T { public void F() { Console.WriteLine("T"); } public T() { F(); } } class TDerived : T, IF { public new void F() { Console.WriteLine("TDerived"); } public TDerived() { F(); } } class Test { static void Main() { T [] tarr = new T[4]; tarr[0] = new T(); tarr[1] = new TDerived(); tarr[2] = new T(); tarr[3] = new TDerived(); foreach(T t in tarr) { IF iif = (IF)t; iif.F(); } } } Результатом выполнения данного примера будет ошибка времени выполнения. В чем проблема? А она кроется в строке IF iif = (IF)t; Дело в том, что элемент tarr[0] ссылается на объект класса T, который не реализует интерфейс IF. Следовательно, при попытке приведения мы получим исключение типа InvalidCastException. В языке C# существует возможность проверить реализует ли данный класс данный интерфейс с помощью оператора is. Задача данного оператора проверить совместим ли тип (времени выполнения) объекта с данным типом. Перепишем пример снова: interface IF { void F(); } class T { public void F() { Console.WriteLine("T"); } public T() { F(); } } class TDerived : T, IF { public new void F() { Console.WriteLine("TDerived"); } public TDerived() { F(); } } class Test { static void Main() { T [] tarr = new T[4]; tarr[0] = new T(); tarr[1] = new TDerived(); tarr[2] = new T(); tarr[3] = new TDerived(); foreach(T t in tarr) { if(t is IF) // Проверка { IF iif = (IF)t; iif.F(); } } } } Вывод на экран: T T TDerived T T TDerived TDerived TDerived******* Можно было, конечно, отловить сбой при помощи обработки исключений, но это слишком загромождает программу. ******* Оператор asЕсли вы заметили, в предыдущем примере выполняется лишнее действие, связанное с тем, что тип объекта проверяется дважды - при выполнении оператора is и при приведении типа. Поэтому в предыдущем примере разумнее воспользоваться оператором as, задача которого попытаться осуществить приведение типов без возбуждения исключительной ситуации (в случае невозможности приведения оператор возвратит null). И снова перепишем пример: interface IF { void F(); } class T { public void F() { Console.WriteLine("T"); } public T() { F(); } } class TDerived : T, IF { public new void F() { Console.WriteLine("TDerived"); } public TDerived() { F(); } } class Test { static void Main() { T [] tarr = new T[4]; tarr[0] = new T(); tarr[1] = new TDerived(); tarr[2] = new T(); tarr[3] = new TDerived(); foreach(T t in tarr) { IF iif = t as IF; if(iif != null) // Проверка { iif.F(); } } } } Вывод на экран: T T TDerived T T TDerived TDerived TDerived******* Операторы is и as могут применяться к классам. ******* Явная реализация интерфейсовВ некоторых случаях вы можете захотеть скрыть реализацию интерфейса от пользователей класса. В этом случае можно применить технологию явной реализации интерфейсов. Пример: interface IA { void f(); } class C : IA { // Явная реализация функции интерфейса; // режим доступа указывать запрещается void IA.f() { ... } } class Test { static void Main() { C c = new C(); IA a = (IA)c; // Вызов данной функции интерфейса возможен только // посредством явного преобразования объекта к // соответствующему интерфейсу a.f(); } } Интерфейсы, основанные на других интерфейсахИнтерфейсы можно объединять, образуя новые интерфейсы. interface IA { void f(); } interface IB { void g(); } interface IC : IA, IB { void h(); } Данный код означает, что класс, реализующий интерфейс IC, должен будет реализовать все три функции интерфейса (f, g, и h). Более подробную информацию можно получить, изучив практические примеры, или заглянув в MSDN. |
|
Библиотека программиста. 2009. |
|