// Класс 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("Эта машина уже помыта…");
}
public void RotateTires(Car с) {
if (c.Rotate) Console.WriteLine("Меняем шины");
else Console.WriteLine("Менять шины не требуется…");
}
}
Теперь проиллюстрируем взаимодействие между новыми типами Car, CarDelegate, Garage и ServiceDepartment, рассмотрев их использование в следующем фрагменте программного кода.
// Garage направляет все заказы в ServiceDepartment
// (найти хорошего механика всегда проблема…)
public class Program {
static void Main(string[] args) {
// Создание гаража.
Garage g = new Garage();
// Создание отделения обслуживания,
ServiceDepartment sd = new ServiceDepartment();
// Garage моет машины и меняет шины,
// делегируя соответствующие полномочия ServiceDepartment.
g.ProcessCars(new Car.CarDelegate(sd.WashCar));
g.ProcessCars(new Car.CarDelegate(sd.RotateTires));
Console.ReadLine();
}
}
На рис. 8.6 показан соответствующий вывод.
Рис. 8.6. Перекладывание ответственности
Анализ программного кода делегирования
Предложенный выше метод Main() начинается с создания экземпляров типов Garage и ServiceDepartment. Когда вы пишете
// Помыть все грязные машины.
g.ProcessCars(new Car.CarDelegate(sd.WashCar));
это на самом деле означает: "Добавить указатель на метод ServiceDepartment.WashCar() к объекту Car.CarDelegate и передать этот объект в Garage.ProcessCars()". Подобно любому автомобильному предприятию в реальном мире, все заказы передаются в отдел технического обслуживания (что и объясняет, почему замена масла, обычно требующая 30 минут, занимает целых 2 часа). С учетом этого ProcessCars() можно интерпретировать так.
// CarDelegate указывает на функцию ServiceDepartment.WashCar.
public void ProсessCars(Car.CarDelegate proc) {
foreach (Car с in theCars)
proc(c); // proc(c) =› ServiceDepartment.WashCar(c)
…
}
Точно так же, если вы говорите
// Поменять шины.
g.ProcessCars(new Car.CarDelegate(sd.RotateTires));
то ProcessCars() можно интерпретировать, как
// CarDelegate указывает на функцию ServiceDepartment.RotateTires.
public void ProcessCars(Car.CarDelegate proc) {
…
foreach(Car с in the Cars)
proc(c); //proc(c) =› ServiceDepartment.RotateTires(e)
…
}
Исходный код. Проект CarGarage размещен в подкаталоге, соответствующем главе 8.
К этому моменту вы должны чувствовать себя более уверенно при создании и использовании типов делегата. Перед тем как перейти к изучению синтаксиса событий в C#, мы рассмотрим новую возможность .NET 2.0, связанную с делегатами и обозначенную термином ковариантность. Вы могли обратить внимание на то, что все делегаты, созданные нами до сих пор, указывали на методы, возвращающие простые числовые типы данных (или не возвращающие значений вообще). Но предположим, что нам нужен делегат, способный указывать на методы, возвращающие пользовательский тип класса.
Читать дальше