Эндрю Троелсен - ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
- Название:ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2007
- Город:Москва • Санкт-Петербург • Киев
- ISBN:ISBN 5-8459-1124-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Эндрю Троелсен - ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание краткое содержание
В этой книге содержится описание базовых принципов функционирования платформы .NET, системы типов .NET и различных инструментальных средств разработки, используемых при создании приложений .NET. Представлены базовые возможности языка программирования C# 2005, включая новые синтаксические конструкции, появившиеся с выходом .NET 2.0, а также синтаксис и семантика языка CIL. В книге рассматривается формат сборок .NET, библиотеки базовых классов .NET. файловый ввод-вывод, возможности удаленного доступа, конструкция приложений Windows Forms, доступ к базам данных с помощью ADO.NET, создание Web-приложений ASP.NET и Web-служб XML. Книга содержит множество примеров программного кода, призванного помочь читателю в освоении предлагаемого материала. Программный код примеров можно загрузить с Web-сайта издательства.
ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Интерфейсы обратного вызова
При рассмотрении материала предыдущей главы вы имели возможность убедиться, что интерфейсы определяют доведение, которое может поддерживаться самыми разными типами. Кроме использований интерфейсов для поддержки полиморфизма, их можно использовать и в качестве механизма обратного вызова. Соответствующий подход дает объектам возможность осуществлять двухсторонний обмен, используя общее множество членов.
Чтобы показать варианты использования интерфейсов обратного вызова, мы изменим уже знакомый нам тип 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("Извините, машина сломалась…");
} else {
currSpeed += delta;
// Отправка события AboutToBlow.
if (10 == maxSpeed – currSpeed) {
foreach(IEngineEvents e in clientSinks) е.AboutToBlow("Осторожно! Могу сломаться!");
}
if (currSpeed ›= maxSpeed) carIsDead = true;
else Console.WriteLine(" \tCurrSpeed = {0} ", currSpeed);
}
}
}
Вот подходящий программный код клиента, в котором используется интерфейс обратного вызова для отслеживания событий Car.
// Создание машины и мониторинг событий.
public class CarApp {
static void Main(string[] args) {
Console.WriteLine("*** Интерфейсы и контроль событий ***");
Car cl = new Car("SlugBug", 100, 10);
// Создание объекта-приемника.
CarEventSink sink = new CarEventSink();
// Передача Car ссылки на приемник.
cl.Advise(sink);
// Ускорение (вызывает наступление событий).
for (int i = 0; i ‹ 10; i++) cl.Accelerate(20);
// Разрыв связи с источником событий.
cl.Unadvise(sink);
Console.ReadLine();
}
}
На рис. 8.1 показан конечный результат работы этого основанного на интерфейсе протокола событий.

Рис. 8.1. Основанный на интерфейсе протокол событий
Обратите внимание на то, что метод Unadvise() позволяет вызывающей стороне селективно отключаться от источника событий. Здесь перед выходом из Main() вызывается Unadvise(), хотя, строго говоря, это и не обязательно. Но предположим, что приложение должно зарегистрировать два приемника, динамически отключить их по очереди в процессе выполнения, а затем продолжить работу.
static void Main(string[] args) {
Console.WriteLine("***** Интерфейсы и контроль событий *****");
Car cl = new Car("SlugBug", 100, 10);
// Создание двух объектов.
Console.WriteLine("***** Создание приемников *****");
CarEventSink sink = new CarEventSink("Первый приемник");
CarEventSink myOtherSink = new CarEventSink("Второй приемник");
// Передача приемников объекту Car.
Console.WriteLine("\n***** Отправка приемников в Car *****");
cl.Advise(sink);
cl.Advise(myOtherSink);
// Ускорение (при этом генерируются события).
Console.WriteLine("\n***** Ускорение *****");
for (int i = 0; i ‹ 10; i++) cl.Accelerate(20);
// Отключение первого приемника событий.
Console.WriteLine("\n***** Отключение первого приемника *****");
cl.Unadvise(sink);
// Новое ускорение (теперь вызывается только myOtherSink).
Console.WriteLine("\n***** Снова ускорение *****);
for(int i = 0; i ‹ 10; i++) cl.Accelerate(20);
// Отключение второго приемника событий.
Console.WriteLine("\n***** Отключение второго приемника *****");
Console.ReadLine();
}
Интерфейсы событий могут быть полезны и тем , что они могут использоваться с любыми языками и любыми платформами (.NET, J2EE или какими-то иными), поддерживающими программирование на основе интерфейсов. Однако "официальный" протокол событий задает платформа .NET. Чтобы понять внутреннюю архитектуру обработки событий, мы начнем с обсуждения роли типа делегата.
Читать дальшеИнтервал:
Закладка: