// Помыть все грязные машины.
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, связанную с делегатами и обозначенную термином ковариантность. Вы могли обратить внимание на то, что все делегаты, созданные нами до сих пор, указывали на методы, возвращающие простые числовые типы данных (или не возвращающие значений вообще). Но предположим, что нам нужен делегат, способный указывать на методы, возвращающие пользовательский тип класса.
// Определение делегата, который позволит указывать на объекты,
// возвращающие типы Car.
public delegate Car ObtainCarDelegate();
Мы можем определить целевой объект для делегата так, как обычно.
class Program {
public delegate Car ObtainCarDelegate();
public static Car GetBasicCar() {return new Car();}
static void Main(string[] args) {
ObtainCarDelegate targetA = new ObtainCarDelegate(GetBasicCar);
Car c = targetA();
Console.ReadLine();
}
}
Пока что все выглядит прекрасно. Но что делать, если мы получим новый класс SportsCar из типа Car и потребуется делегат, который сможет указывать на методы, возвращаемые этим новым типом класса? До появления .NET 2.0 в таком случае вам пришлось бы определить новый делегат.
// Новый делегат, указывающий на целевые объекты,
// возвращающие типы SportsCar.
public delegate SportsCar ObtainSportsCarDelegate();
У нас теперь два типа делегата, и мы должны создать по экземпляру каждого из них, чтобы получить типы Car и SportsCar.
class Program {
public delegate Car
public delegate SportsCar
public static Car
public static SportsCar
static void Main(string[] args) {
ObtainCarDelegate targetA = new ObtainCarDelegate(GetBasicCar);
Car
ObtainSportsCarDelegate targetB = new ObtainSportsCarDelegate(GetSportsCar);
SportsCar
Console.ReadLine();
}
}