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

Делегаты в качестве параметров

Делегаты в качестве параметров

Теперь, когда у нас есть новый тип делегата, который указывает на методы, получающие 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("Эта машина уже помыта…");
 }
 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. Перекладывание ответственности

Оглавление книги


Генерация: 4.224. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз