Чтение онлайн

на главную - закладки

Жанры

ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание

Троелсен Эндрю

Шрифт:

Помимо возможности создания пользовательских интерфейсов, вы имеете возможность использовать ряд стандартных интерфейсов, определенных в библиотеках .NET (т.е. предлагаемых каркасом приложений). Вы можете строить пользовательские типы, реализующие эти встроенные интерфейсы, чтобы обеспечить выполнение ряда стандартных действий, таких как клонирование, сортировка или перечисление. Наконец, в этой главе вы узнали о классах коллекций, определенных в пространстве имен System.Collections, и изучили ряд общих интерфейсов, которые используются связанными с коллекциями типами.

ГЛАВА 8. Интерфейсы обратного вызова, делегаты и события

До

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

Затем вы узнаете о типе делегата .NET, который является объектом, обеспечивающим типовую безопасность и "указывающим" на метод или методы, которые могут быть вызваны позднее. Но, в отличие от традиционного указателя на функцию в C++, делегаты .NET представляют собой объекты, которые имеют встроенную поддержку многоадресного и асинхронного вызова методов. Мы рассмотрим асинхронное поведение типов делегата позже, при изучении пространства имен System.Threading (см. главу 14).

Выяснив, как создавать типы делегата и работать с ними, мы с вами рассмотрим ключевое слово C# event, которое призвано упростить и ускорить работу с типами делегата. Наконец, в этой главе будут рассмотрены новые возможности языка C#, связанные с использованием делегатов и событий, включая анонимные методы и групповые преобразования методов, Вы увидите, что указанный подход открывает более короткий путь к целевым объектам соответствующих событий.

Интерфейсы обратного вызова

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

Чтобы показать варианты использования интерфейсов обратного вызова, мы изменим уже знакомый нам тип Car так, чтобы он мог информировать вызывающую сторону о приближении поломки машины (т.е. о том, что текущая скорость на 10 км/ч ниже максимальной скорости) и о свершившейся поломке (когда текущая скорость равна или выше максимальной скорости). Способность посылать и принимать соответствующие события будет реализована с помощью интерфейса, носящего имя IEngineEvents.

// Интерфейс обратного вызова.

public interface IEngineEvents {

 void AboutToBlow(string msg);

 void Exploded (string msg);

}

Интерфейсы событий обычно реализуются не объектом, непосредственно "заинтересованным" в получении событий, а некоторым вспомогательным объектом, который называется объектом-приемником. Отправитель событий (в данном случае это тип Car) при определенных условиях выполняет

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

// Приемник событий Car.

public class CarEventSink: IEngineEvents {

 private string name;

 public CarEventSink{}

 public CarEventSink(string sinkName) { name = sinkName; }

 public void AboutToBlow(string msg) { Console.WriteLine("{0} сообщает: {1}", name, msg); }

 public void Exploded(string msg) { Console.WriteLine(" {0} сообщает: {1}", name, msg); }

}

Теперь, когда у нас есть объект-приемник, реализующий интерфейс событий, нашей следующей задачей является передача ссылки на этот приемник в тип Car. Тип Car будет хранить эту ссылку и при необходимости выполнять обратные вызовы приемника. Чтобы тип Car мог получить ссылку на приемник, нужно добавить в тип Car вспомогательный член, который мы назовем Advise. Точно так же. если вызывающая сторона пожелает отменить привязку к источнику событий, она может вызвать другой вспомогательный метод типа Car – метод Unadvise. Наконец, чтобы позволить вызывающей стороне регистрировать множество приемников событий (с целью групповой адресации), тип Car поддерживает ArrayList для представления исходящих соединений.

// Тип Car и вызывающая сторона могут связываться

// с помощью интерфейса IEngineEvents.

public class Car {

 // Набор связанных приемников.

 ArrayList clientSinks = new ArrayList;

 // Присоединение к источнику событий или отсоединение от него.

 public void Advise(IEngineEvents sink) {clientSinks.Add(sink);}

 public void Unadvise(IEngineEvents sink) {clientSinks.Remove(sink);}

 …

}

Чтобы на самом деде посылать события, мы обновим метод Car.Accelerate так, чтобы он осуществлял "проход" по соединениям, указанным в ArrayList, и при необходимости выдавал подходящее сообщение (обратите внимание на то, что теперь в классе Car есть член-переменная carIsDead логического типа для представления состояния двигателя машины).

// Протокол событий на базе интерфейса.

class Car {

 …

 // Эта машина работает или нет?

 bool carIsDead;

 public void Accelerate(int delta) {

// Если машина 'сломалась', отправить событие Exploded

// каждому приемнику.

if (carIsDead) {

foreach(IEngineEvents e in clientSinks) e.Exploded("Извините, машина сломалась…");

Поделиться:
Популярные книги

Шайтан Иван 2

Тен Эдуард
2. Шайтан Иван
Фантастика:
боевая фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Шайтан Иван 2

Наследник старого рода

Шелег Дмитрий Витальевич
1. Живой лёд
Фантастика:
фэнтези
8.19
рейтинг книги
Наследник старого рода

Аргумент барона Бронина 2

Ковальчук Олег Валентинович
2. Аргумент барона Бронина
Фантастика:
попаданцы
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Аргумент барона Бронина 2

Третье правило дворянина

Герда Александр
3. Истинный дворянин
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Третье правило дворянина

Убивать чтобы жить 3

Бор Жорж
3. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 3

СД. Том 15

Клеванский Кирилл Сергеевич
15. Сердце дракона
Фантастика:
героическая фантастика
боевая фантастика
6.14
рейтинг книги
СД. Том 15

Жена неверного маршала, или Пиццерия попаданки

Удалова Юлия
Любовные романы:
любовно-фантастические романы
4.25
рейтинг книги
Жена неверного маршала, или Пиццерия попаданки

Мымра!

Фад Диана
1. Мымрики
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Мымра!

Идеальный мир для Лекаря 12

Сапфир Олег
12. Лекарь
Фантастика:
боевая фантастика
юмористическая фантастика
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 12

Оцифрованный. Том 1

Дорничев Дмитрий
1. Линкор Михаил
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Оцифрованный. Том 1

Элита элит

Злотников Роман Валерьевич
1. Элита элит
Фантастика:
боевая фантастика
8.93
рейтинг книги
Элита элит

Хуррит

Рави Ивар
Фантастика:
героическая фантастика
попаданцы
альтернативная история
5.00
рейтинг книги
Хуррит

Шаман. Похищенные

Калбазов Константин Георгиевич
1. Шаман
Фантастика:
боевая фантастика
попаданцы
6.44
рейтинг книги
Шаман. Похищенные

Курсант: Назад в СССР 4

Дамиров Рафаэль
4. Курсант
Фантастика:
попаданцы
альтернативная история
7.76
рейтинг книги
Курсант: Назад в СССР 4