Скачиваний:
60
Добавлен:
24.03.2015
Размер:
303.62 Кб
Скачать

17.3. Многоадресные экземпляры делегатов

До сих пор мы рассматривали делегаты, каждый экземпляр которых представляет только один конкретный метод. Однако делегат (его экземпляр) может содержать ссылки сразу на несколько методов, соответствующих типу делегата. При обращении к такому экземпляру делегата в этом случае автоматически организуется последовательный вызов всех методов, которые он представляет.

Для поддержки такой многоадресности используются методы, которые каждый делегат наследует от базового класса MulticastDelegate, который в свою очередь является наследником класса System.Delegate. Рассмотрим основные из них.

public static Delegate Combine(Delegate a, Delegate b) - метод объединяет два экземпляра делегата, создавая двухадресный экземпляр делегата. Аргументами при обращении должны быть две ссылки на экземпляры делегатов. Обращание к этому варианту метода Combine() для упрощения можно заменять операцией "+ = " или последовательностью операций "+" и"=":

многоадресный_делегат+=ссылка на делегат;

public static Delegate Combine (params Delegate[] delegates) - метод объединяет несколько экземпляров делегатов. Аргументы - список ссылок на экземпляры делегатов. Метод открытый и статический, то есть принадлежит типу делегатов. Возвращаемое значение - экземпляр делегата.

public virtual Delegate[] GetlnvocationList() – метод возвращает массив экземпляров делегатов, объединенных в конкретном многоадресном экземпляре делегата, к которому применен данный метод. Метод открытый нестатический и виртуальный. Автоматически переопределяется при объявлении каждого типа делегатов. Применим к конкретным экземплярам делегатов. Список аргументов не нужен. Возвращаемое значение - массив экземпляров делегатов (ссылок на них), представляющих все методы, которые адресует экземпляр делегата.

public static Delegate Remove(Delegate source, Delegate value) – метод удаляет из многоадресного экземпляра делегата, заданного первым параметром, конкретную ссылку, заданную вторым параметром-делегатом. Метод открытый и статический, то есть принадлежит типу делегатов. Аргументами при обращении должны быть две ссылки на экземпляры-делегаты. Первый аргумент представляет многоадресный экземпляр делегата, второй представляет экземпляр делегата, значение которого (ссылку на метод) нужно удалить из многоадресного экземпляра делегата. Обращание к методу Remove() можно заменять эквивалентной ему операцией "-=" или последовательностью операций "-" и "=":

Многоадресный_делегат -= ссылка_на_делегат;

На примере с классом, моделирующим движения робота, мы уже показали, как с помощью массива делегатов можно составлять и использовать цепочки вызовов методов.

Применение многоадресных экземпляров делегатов позволяет в рассмотренном выше примере расширить систему команд управления роботом, не изменяя его внутренней структуры. В следующей программе (17_03.cs) тот же класс Robot и тот же тип делегатов Steps по-другому используются в методе Main():

static void Main()

{

Robot rob = new Robot(); // конкретный робот

Steps delR = new Steps(rob.right); // направо

Steps delL = new Steps(rob.left); // налево

Steps delF = new Steps(rob.forward); // вперед

Steps delB = new Steps(rob.backward); // назад

// шаги по диагоналям:

Steps delRF = delR + delF;

Steps delRB = delR + delB;

Steps delLF = delL + delF;

Steps delLB = delL + delB;

delLB(); // перемещение влево и назад

rob.position(); // сообщить координаты

delRB(); // перемещение вправо и назад

rob.position(); // сообщить координаты

}

В программе определены ссылка rob, именующая объект класса Robot, и для этого объекта определены экземпляры делегата (ссылки: deIR, delL, delF, delB), именующие методы его покоординатных перемещений по плоскости. Затем определены четыре многоадресных (двухадресных) экземпляра делегата (ссылки: delRF, delRB, delLF, delLB), применение которых позволяет перемещать робот по диагоналям.

Результат выполнения программы:

The Robot position: x=-1, y=-1

The Robot position: x=0, y=-2

Обращение к экземпляру многоадресного делегата приводит к последовательному исполнению цепочки методов, которые представленыделегатами. Результат выполнения цепочки делегатов – то значение, которое возвращает последний делегат цепочки. Стандарт не определяет порядка вызова методов, адресованных многоадресным делегатам. Нельзя быть уверенным, что вызов будет происходить в том порядке, в котором экземпляры делегатов добавлялись к многоадресному делегату. Отметим, что наиболее часто многоадресные делегаты применяются для представления цепочек ссылок на методы, каждый из которых возвращает значение типа void.

Если любой из делегатов цепочки пошлёт исключение, то обработка цепочки прерывается и выполняется поиск подходящего обработчика исключений.

Если делегаты цепочки принимают параметры по ссылке, то изменения таких параметров воспринимаются следующими делегатами цепочки.

Значения, возвращаемые методами Combine() и Remove(), имеют системный тип Delegate. Поэтому для корректного обращения к многоадресному делегату рекомендуется выполнять приведение типов (это не сделано в приведённом примере).

Имеется возможность вызывать делегаты цепочки в произвольном порядке и получать возвращаемые значения каждого из них. Для этого используется уже упомянутый нестатический метод GetlnvocationList(), определённый в классе System.Delegate. Он возвращает массив делегатов Delegate[], входящих в тот многоадресный делегат, к которому метод применён.

Получив массив делегатов можно использовать его экземпляры в произвольном порядке...

Соседние файлы в папке Lekc_C#