Нашли ошибку или опечатку? Выделите текст и нажмите

Поменять цветовую

гамму сайта?

Поменять
Обновления сайта
и новые разделы

Рекомендовать в Google +1

Групповой вызов и адресация делегируемых методов

73

Групповое преобразование делегируемых методов

Еще в версии C# 2.0 было внедрено специальное средство, существенно упрощающее синтаксис присваивания метода делегату. Это так называемое групповое преобразование методов, позволяющее присвоить имя метода делегату, не прибегая к оператору new или явному вызову конструктора делегата.

using System;

namespace ConsoleApplication1
{
    // Создадим делегат
    delegate int IntOperation (int i, int j);

    class Program
    {
        // Организуем ряд методов
        static int Sum(int x, int y)
        {
            return x + y;
        }

        static int Prz(int x, int y)
        {
            return x * y;
        }

        static int Del(int x, int y)
        {
            return x / y;
        }

        static void Main()
        {
            // Присваиваем имя метода обычным способом
            IntOperation op1 = new IntOperation(Sum);
            // Используем групповое преобразование
            op1 = Sum;

            int result = op1(5, 10);
            Console.WriteLine("Сумма: " + result);

            // Изменим ссылку на метод
            op1 = Prz;
            result = op1(5, 10);
            Console.WriteLine("Произведение: " + result);

            Console.ReadLine();
        }
    }
}

Синтаксис группового преобразования методов существенно упрощен по сравнению с прежним подходом к делегированию.

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

В предыдущем примере использовались статические методы, но делегат может ссылаться и на методы экземпляра, хотя для этого требуется ссылка на объект. Так, ниже приведен измененный вариант предыдущего примера, в котором операции с числами инкапсулируются в классе MyClass. Следует заметить, что в данном случае может быть также использован синтаксис группового преобразования методов:

using System;

namespace ConsoleApplication1
{
    // Создадим делегат
    delegate int IntOperation (int i, int j);

    public class MyClass
    {
        public static int Sum(int x, int y)
        {
            return x + y;
        }

        public static int Prz(int x, int y)
        {
            return x * y;
        }

        public static int Del(int x, int y)
        {
            return x / y;
        }
    }

    class Program
    {
        static void Main()
        {
            // Инициализируем делегат
            IntOperation op1 = MyClass.Sum;

            int result = op1(5, 10);
            Console.WriteLine("Сумма: " + result);

            op1 = MyClass.Prz;
            result = op1(5, 10);
            Console.WriteLine("Произведение: " + result);

            Console.ReadLine();
        }
    }
}

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

Групповая адресация

Одним из самых примечательных свойств делегата является поддержка групповой адресации. Попросту говоря, групповая адресация — это возможность создать список, или цепочку вызовов, для методов, которые вызываются автоматически при обращении к делегату. Создать такую цепочку нетрудно. Для этого достаточно получить экземпляр делегата, а затем добавить методы в цепочку с помощью оператора + или +=. Для удаления метода из цепочки служит оператор - или -=. Если делегат возвращает значение, то им становится значение, возвращаемое последним методом в списке вызовов. Поэтому делегат, в котором используется групповая адресация, обычно имеет возвращаемый тип void.

using System;

namespace ConsoleApplication1
{
    delegate void OpStroke (ref int[] arr);

    public class ArrOperation
    {
        public static void WriteArray(ref int[] arr)
        {
            Console.WriteLine("Исходный массив: ");
            foreach (int i in arr)
                Console.Write("{0}\t", i);
            Console.WriteLine();
        }

        // Сортировка массива
        public static void IncSort(ref int[] arr)
        {
            int j,k;
            for (int i = 0; i < arr.Length - 1; i++)
            {
                j = 0;
                do
                {
                    if (arr[j] > arr[j + 1])
                    {
                         k = arr[j];
                         arr[j] = arr[j+1];
                         arr[j+1] = k;
                     }
                     j++;
                }
                while (j < arr.Length - 1);
            }

            Console.WriteLine("Отсортированный массив в большую сторону: ");
            foreach (int i in arr)
                Console.Write("{0}\t",i);
            Console.WriteLine();
        }

        public static void DecSort(ref int[] arr)
        {
            int j, k;
            for (int i = 0; i < arr.Length - 1; i++)
            {
                j = 0;
                do
                {
                    if (arr[j] < arr[j + 1])
                    {
                        k = arr[j];
                        arr[j] = arr[j + 1];
                        arr[j + 1] = k;
                    }
                    j++;
                }
                while (j < arr.Length - 1);
            }

            Console.WriteLine("Отсортированный массив в меньшую сторону: ");
            foreach (int i in arr)
                Console.Write("{0}\t", i);
            Console.WriteLine();
        }

        // Заменяем нечетные числа четными и наоборот
        public static void ChetArr(ref int[] arr)
        {
            Console.WriteLine("Четный массив: ");
            for (int i = 0; i < arr.Length; i++)
                if (arr[i] % 2 != 0)
                    arr[i] += 1;

            foreach (int i in arr)
                Console.Write("{0}\t", i);
            Console.WriteLine();
        }

        public static void NeChetArr(ref int[] arr)
        {
            Console.WriteLine("Нечетный массив: ");
            for (int i = 0; i < arr.Length; i++)
                if (arr[i] % 2 == 0)
                    arr[i] += 1;

            foreach (int i in arr)
                Console.Write("{0}\t", i);
            Console.WriteLine();
        }
    }

    class Program
    {
        static void Main()
        {
            int[] myArr = new int[6] { 2, -4, 10, 5, -6, 9 };

            // Структуируем делегаты
            OpStroke Del;
            OpStroke Wr = ArrOperation.WriteArray;
            OpStroke OnSortArr = ArrOperation.IncSort;
            OpStroke OffSortArr = ArrOperation.DecSort;
            OpStroke ChArr = ArrOperation.ChetArr;
            OpStroke NeChArr = ArrOperation.NeChetArr;

            // Групповая адресация
            Del = Wr;
            Del += OnSortArr;
            Del += ChArr;
            Del += OffSortArr;
            Del += NeChArr;

            // Выполняем делегат
            Del(ref myArr);

            Console.ReadLine();
        }
    }
}
Групповая адресация

Цепочки вызовов являются весьма эффективным механизмом, поскольку они позволяют определить ряд методов, выполняемых единым блоком. Благодаря этому улучшается структура некоторых видов кода. Кроме того, цепочки вызовов имеют особое значение для обработки событий.

Alexandr Erohin ✯ alexerohinzzz@gmail.com © 2011 - 2017