C#. Часть 3. Делегаты. Групповая адресация. Создание цепочек вызовов методов




Часть 3. Делегаты. Групповая адресация. Создание цепочек вызовов методов

Данная тема базируется на предыдущей теме:


Содержание


Поиск на других ресурсах:

1. Что означает термин «групповая адресация методов»?

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

 

2. Какие преимущества дает использование групповой адресации при работе с делегатами?

Групповая адресация позволяет сформировать списки (цепочки) вызовов. Это есть эффективным, поскольку:

  • можно гибко формировать списки методов, которые должны вызываться по одному вызову делегата;
  • удобно формировать списки методов, которые выполняют разные виды работ над некоторым общим объектом;
  • улучшается структура программного кода;
  • удобно обрабатывать события, которые генерируются системой.

 

3. Какие операции используются при групповой адресации?

Для организации групповой адресации методов с помощью делегата используются 4 операции:

  • операции ‘+’ и ‘+=’ – добавляют метод к списку методов;
  • операции ‘−’ и ‘−=’ – удаляют метод из списка методов.

 

4. Пример добавления и удаления методов в списке

Пусть даны методы с именами Method1(), Method2(), Method3(). Пусть задан делегат с именем List.

Нижеследующий код демонстрирует использование операций ‘+’, ‘+=’, ‘−’, ‘−=’.

Чтобы добавить метод Method2 к делегату (списку) List, нужно выполнить такой код:

List = List + Method2;

Другой способ добавления метода

ListM += Method2;

Чтобы удалить метод Method2 нужно написать:

List = List - Method2;

или

ListM -= Method2;

 

5. Что произойдет, если попробовать удалить метод, которого нет в списке методов?

Ничего не произойдет. Если метода с именем M нет в списке (цепочке) методов, тогда строка удаления (операция ‘−’ или ‘−=’) пропускается.

 

6. Как работает групповая адресация, если делегат возвращает значение?

Если в делегате сформирован список методов возвращающих некоторый тип, отличный от типа void, тогда результатом вызова будет результат возвращаемый последним методом  в списке.

Чтобы получить результат работы всех методов списка, нужно использовать метод GetInvocationList(). Этот метод возвращает массив всех методов, которые были сформированы в делегате в виде списка.

 

7. Как работает групповая адресация, если делегат возвращает тип void?

Если делегат возвращает тип void, то при вызове делегата будут вызываться все методы, которые сформированы в список (цепочку) с помощью групповой адресации.

Последовательность вызова методов соответствует последовательности добавления методов к списку. Первый добавленный метод будет вызван первым, второй добавленный метод будет вызван вторым и т.д.

 



8. Пример, который демонстрирует использование групповой адресации для делегатов, которые возвращают значение (методы возвращают значение)

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

Пример.

Даны объявления типа делегата CalcFigures, возвращающего значение типа double:

// Объявление типа делегата, который возвращает значение
delegate double CalcFigures(double r);

Дано описание статических методов, которые будут формироваться в список:

// Объявление статических методов класса
// длина окружности
public static double Get_Lentgh(double r)
{
    double length = 3.1415 * r * 2;
    return length;
}

// площадь круга
public static double Get_Area(double r)
{
    double area = 3.1415 * r * r;
    return area;
}

// объем шара
public static double Get_Volume(double r)
{
    double volume = 4.0 / 3.0 * 3.1415 * r * r * r;
    return volume;
}

В другом программном коде (например, обработчике события) объявляются делегаты и формируется список (группа) методов, на которые ссылается делегат:

// Объявление делегатов
CalcFigures CF;
CalcFigures GetL = Get_Lentgh;
CalcFigures GetA = Get_Area;
CalcFigures GetV = Get_Volume;

...

// организовать групповую адресацию
CF = GetL; // CF ссылается на метод Get_Length: CF->Get

// добавить к списку CF метод Get_Volume
CF = CF + GetV; // или CF += GetV;

// добавить к списку CF метод Get_Area
CF += GetA; // CF => Get_Length->Get_Volume->Get_Area
result = CF(3.0); // result = 28.2735 - вызовется метод Get_Area

// удалить из списка CF метод Get_Area
CF -= GetA; // CF => Get_Length->Get_Volume
result = CF(3.0); // result = 113.094 - вызывается метод Get_Volume

// добавить снова метод Get_Length
CF += GetL; // CF => Get_Length->Get_Volume->Get_Length
result = CF(3.0); // result = 18.849 - вызовется Get_Length

// удалить метод Get_Length
CF -= GetL; // CF => Get_Length->Get_Volume
result = CF(3.0); // result = 113.094 - вызовется Get_Volume

// удалить снова Get_Length
CF -= GetL; // CF => Get_Volume - в списке остался один метод Get_Volume
result = CF(3.0); // result = 113.094

// удалить последний метод Get_Volume
CF -= GetV; // CF => список пустой

 

9. Пример, демонстрирующий использование групповой адресации для делегатов, возвращающих тип void

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

  • умножение x на 2 (метод Mult2());
  • умножение x на 3 (метод Mult3());
  • квадрат числа x (метод Sqr()).

Объявление тип делегата выглядит следующим образом:

// Объявление типа делегата
delegate void CalcNumber(ref double x);

Объявление методов

// методы, что оперируют вещественным числом x
// умножение числа на 2
public static void Mult2(ref double x)
{
    x = x * 2;
}

// умножение числа на 3
public static void Mult3(ref double x)
{
    x = x * 3;
}

// квадрат числа x
public static void Sqr(ref double x)
{
    x = x * x;
}

Демонстрация групповой адресации для делегата, возвращающего тип void из другого программного кода (например, обработчика события):

// объявление делегата
CalcNumber CN;

// переменная, которая будет обрабатываться методами
double x;

// Создание цепочки методов - 1
CN = Mult2; // CN => Mult2
CN += Mult2; // CN => Mult2 -> Mult2
CN += Sqr; // CN => Mult2 -> Mult2 -> Sqr
CN = CN + Mult3; // CN => Mult2 -> Mult2 -> Sqr -> Mult3

x = 2.0;
CN(ref x); // x = 192 = ((2.0 * 2 * 2)^2 ) * 3

// Удаление из цепочки всех методов
CN -= Mult3;
CN -= Mult2;
CN -= Mult2;
CN -= Sqr; // CN => список пустой

// Создание цепочки методов - 2
CN = Sqr; // CN => Sqr
CN += Sqr; // CN => Sqr -> Sqr
CN += Mult3; // CN => Sqr -> Sqr -> Mult3
CN += Mult2; // CN => Sqr -> Sqr -> Mult3 -> Mult2

x = 2.0;
CN(ref x); // x = 96 = (2.0 ^ 2 ^ 2) * 3 * 2

 


Связанные темы