На этом шаге мы рассмотрим особенности использования такой адресации.
Делегаты поддерживают многократную адресацию. Это означает, что экземпляр делегата может ссылаться не на один, а сразу на несколько методов. Если так, то при вызове делегата выполняется цепочка вызовов: последовательно вызываются методы, на которые ссылается вызываемый экземпляр делегата. Методы вызываются в той последовательности, в которой ссылки на методы добавлялись экземпляру делегата. Для добавления ссылки на метод экземпляру делегата используется оператор += (команда вида экземпляр+=метод) или полная версия операции присваивания вида экземпляр=экземпляр+метод.
Таким образом, мы можем связать с экземпляром делегата не только отдельный метод, но и целый список методов. Если впоследствии нам понадобится удалить ссылку на метод из списка методов, на которые ссылается экземпляр делегата, можно воспользоваться оператором -= (команда вида экземпляр-=метод) или командой вида экземпляр=экземпляр-метод. В примере ниже представлена программа, в которой используется многократная адресация для экземпляра делегата.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace pr168_1 { // Объявление делегата: delegate void MyDelegate(); // Класс: class MyClass { // Текстовое поле: public string name; // Конструктор с текстовым аргументом: public MyClass(string txt) { name = txt; } // Метод без аргументов: public void show() { Console.WriteLine(name); } } // Класс с главным методом: class Program { // Статический метод без аргументов: static void makeLine() { Console.WriteLine("--------"); } // Главный метод: static void Main() { // Создание объектов: MyClass A = new MyClass("Объект A"); MyClass B = new MyClass("Объект B"); MyClass C = new MyClass("Объект C"); // Объявление переменной делегата: MyDelegate meth; // Присваивание переменной делегата ссылки на метод: meth = A.show; // Вызов экземпляра делегата: meth(); // Присваивание переменной делегата нового значения: meth = makeLine; // Добавление методов в список вызова: meth += A.show; meth += B.show; meth = meth + C.show; // Вызов экземпляра делегата: meth(); // Удаление метода из списка вызова: meth -= B.show; // Вызов экземпляра делегата: meth(); // Удаление метода из списка вызова: meth = meth - A.show; // Вызов экземпляра делегата: meth(); // Задержка: Console.ReadLine(); } } }
Результат выполнения программы следующий:
Рис.1. Результат выполнения программы
Делегат MyDelegate объявлен командой
delegate void MyDelegate(); .
Экземпляры делегата могут ссылаться на методы, не имеющие аргументов и не возвращающие результат. В программе описывается класс MyClass с открытым текстовым полем name. У класса есть конструктор с текстовым аргументом, который присваивается в качестве значения полю name создаваемого объекта. Также в классе описан метод show(), при вызове отображающий в консольном окне значение текстового поля name. У метода нет аргументов, и он не возвращает результат.
В классе Program, кроме главного метода Main(), есть еще и статический метод makeLine(). У метода makeLine() нет аргументов, и он не возвращает результат. При вызове метода в консольном окне отображается импровизированная "линия" из дефисов.
В методе Main() последовательно создаются три объекта A, B и C класса MyClass. Поле name каждого из объектов получает уникальное текстовое значение. Командой
MyDelegate meth;
meth = A.show; ,
При выполнении команды meth() из объекта A вызывается метод show(). Затем выполняется команда
meth = makeLine; .
meth += A.show;
meth += B.show;
meth = meth + C.show;
После выполнения команды
meth -= B.show;
meth = meth - A.show; ,
Методы в списке вызовов могут возвращать результат. Если так, то при вызове экземпляра делегата, ссылающегося на список вызовов, результатом возвращается значение, возвращаемое последним методом в списке вызовов.
На следующем шаге мы рассмотрим использование делегатов.