- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен
Шрифт:
Интервал:
Закладка:
public class Car {
// Добавление элемента в список вызовов.
public void OnAboutToBlow(AboutToBlow clientMethod) {almostDeadList += clientMethod;}
public void OnExploded(Exploded clientMethod) {explodedList += clientMethod;}
…
}
Теперь вызывающая сторона может зарегистрировать несколько целевых объектов.
class Program {
static void Main(string[] args) {
Car c1 = new Car("SlugBug", 100, 10);
// Регистрация множества обработчиков событий.
c1.OnAboutToBlow(new Car.AboutToBlow(CarAboutToBlow));
c1.OnAboutToBlow(new Car.AboutToBlow(CarlsAlmostDoomed));
c1.OnExploded(new Car.Exploded(CarExploded));
…
}
// Car будет вызывать эти методы.
public static void CarAboutToBlow(string msg) {Console.WriteLine (msg);}
public static void CarIsAlmostDoomed(string msg) {Console.WriteLine("Важное сообщение от Car: {0}", msg);}
public static void CarExploded(string msg) {Console.WriteLine(msg);}
}
В программном воде CIL операция += преобразуется в вызов статического метода Delegate.Combine() (можно было бы вызвать Delegate.Combine() непосредственно, но операция += предлагает более простую альтернативу). Взгляните, например, на CIL-представление метода OnAboutToBlow().
.method public hidebysig instance void OnAboutToBlow (class CarDelegate.Car/AboutToBlow clientMethod) cil managed {
.maxstack 8
ldarg.0
dup
ldfld class CarDelegate.Car/AboutToBlow CarDelegate.Car::almostDeadList
ldarg.1
call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
castclass CarDelegate.Car/AboutToBlow
stfld class СarDelegate.Car/AboutToBlow CarDelegate.Car::almostDeadList
ret
}
Класс Delegate определяет также статический метод Remove(), который позволит вызывающей стороне динамически удалять элементы из списка вызовов. Легко догадаться, что в C# разработчики могут для этого использовать перегруженную операцию -=. Чтобы предоставить вызывающей стороне возможность не привязываться к обозначениям AboutToBlow и Exploded, можно добавить в тип Car следующие вспомогательные методы (обратите внимание на операцию -=).
public class Car {
// Удаление элемента из списка вызовов.
public void RemoveAboutToBlow(AboutToBlow clientMethod) {almostDeadList -= clientMethod;}
public void RemoveExploded(Exploded clientMethod) {explodedList -= clientMethod;}
...
}
Здесь синтаксис -= тоже выступает в качестве простого сокращения для вызова статического метода Delegate.Remove(), что доказывается следующим программным кодом CIL для члена RemoveAboutToBlow() типа Car.
.method public hidebysig instance void RemoveAboutToBlow(class CarDelegate.Car/AboutToBlow clientMethod) cil managed {
.maxstack 8
ldarg.0
dup
ldfld class CarDelegate.Car/AboutToBlow CarDelegate.Car::almostDeadList
ldarg.1
call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate, class [mscorlib]System.Delegate)
castclass CarDelegate.Car/AboutToBlow
stfld class CarDelegate.Car/AboutToBlow CarDelegate.Car::almostDeadList
ret
}
Если вызывающая сторона пожелает удалить элемент из списка вызовов делегата, мы должны предоставить тот же объект делегата, который был ранее добавлен. Поэтому мы можем прекратить выдачу сообщения Exploded, обновив Main() так, как показано ниже.
static void Main(string[] args) {
Car cl = new Car("SlugBug", 100, 10);
// Сохранение объекта Car.Exploded делегата.
Car.Exploded d = new Car.Exploded(CarExploded);
cl.OnExploded(d);
…
// Удаление метода CarExploded из списка вызовов.
cl.RemoveExploded(d);
…
}
Вывод нашего приложения CarDelegate показан на рис. 8.5.
Рис. 8.5. Приложение CarDelegate за работой
Исходный код. Проект CarDelegate размещен в подкаталоге, соответствующем главе 8.
Более совершенный пример делегата
Чтобы продемонстрировать более интересные варианты использования делегатов, мы добавим в класс Car пару членов-переменных логического типа. Первый из добавляемых членов предназначен для индикации того, что автомобиль необходимо помыть (isDirty), а второй будет сообщать о том, что автомобиль требует замены шин (shouldRotate). Чтобы позволить пользователю объекта взаимодействовать с этими новыми данными состояния, для Car определяются необходимые дополнительные свойства и обновляется конструктор. Вот как выглядит соответствующим образом модифицированный программный код.
// Обновленный класс Car.
public class Car {
…
// Не пора ли помыть? Не пора ли сменить шины?
private bool isDirtу;
private bool shouldRotate;
// Дополнительные параметры для установки булевых значений.
public Car(string name, int maxSp, int currSp, bool washCar, bool rotateTires) {
…
isDirty = washCar;
shouldRotate = rotateTires;
}
public bool Dirty {
get { return isDirty; }
set { isDirty = value; }
}
public bool Rotate {
get { return shouldRotate; }
set { shouldRotate = value; }
}
}
Также предположим, что в тип Car вложен новый делегат CarDelegate.
// Для Car определяется еще один делегат.
public class Car {
…
// Может вызывать любой метод, получающий Car в виде параметра
// и не возвращающий ничего.
public delegate void CarDelegate(Car с);
…
}
Здесь создается делегат с именем CarDelegate. Тип CarDelegate представляет "некоторую функцию", принимающую Car в качестве параметра и возвращающую пустое значение.
Делегаты в качестве параметров
Теперь, когда у нас есть новый тип делегата, который указывает на методы, получающие Car в виде параметра и не возвращающие ничего, мы можем создавать функции, которые принимают этот делегат в виде параметра. Для примера предположим, что у нас есть новый класс, которому назначено имя Garage (гараж). Этот тип поддерживает коллекцию типов Car, содержащихся в System.Collections. ArrayList. При создании ArrayList наполняется типами Car.
// Класс Garage хранит список типов Car.
using System.Collections;
…
public class Garage {
// Создание списка всех машин в гараже.
ArrayList theCars = new ArrayList();
// Создание машин в гараже.
public Garage() {
// Напомним, что конструктор был обновлен,
// и теперь можно установить значения isDirty и shouldRotate.
theCars.Add(new Car("Viper", 100, 0, true, false));
theCars.Add(new Car("Fred", 100, 0, false, false));
theCars.Add(new Car("BillyBob", 100, 0, false, true));
}
}
Класс Garage будет определять общедоступный метод ProcessCars(), который в качестве единственного аргумента получит новый тип делегата (Car.CarDelegate). В ProcessCars() каждый объект Car из коллекции будет передаваться в виде параметра "той функции, на которую указывает" делегат. При этом ProcessCars() использует члены Target и Method из System.MulticastDelegate, чтобы определить, на какую из функций делегат указывает в настоящий момент.
// Класс Garage имеет метод, использующий CarDelegate.
using System.Collections;
…
public class Garage {
…
// Этот метод получает Car.CarDelegate в виде параметра.
public void ProcessCars(Car.CarDelegate proc) {
// Куда направить вызов?
Console.WriteLine("***** Вызывается: {0} *****", proc.Method);
// Вызывается метод экземпляра или статический метод?
if (proc.Target != null) Console.WriteLine("-›Цель: {0} ", proc.Target);
else Console.WriteLine("-›Целевым является статический метод");
// Вызов "указанного" метода всех машин по очереди.
foreach (Car с in theCars) {
Console.WriteLine("n-› Обработка Car");
proc(c);
}
}
}
Как и в случае любого делегата, при вызове ProcessCars() мы должны указать имя метода, который обработает запрос. Напомним, что такой метод может быть или статическим, или методом экземпляра. Для примера предположим, что в качестве такого метода будут использоваться члены экземпляра нового класса ServiceDepartment (отдел технического обслуживании), которым назначены имела WashCar() и RotateTires(). Обратите внимание на то, что эти два метода используют новые свойства Rotate и Dirty типа Car.
// Этот класс определяет методы, которые будут вызываться
// типом Car.CarDelegate.
public class ServiceDepartment {
public void WashCar(Car c) {
if (c.Dirty) Console.WriteLine("Моем машину");
else Console.WriteLine("Эта машина уже помыта…");