Шаг 171.
Язык программирования C#. Начала.
Делегаты и события. Использование делегатов (еще продолжение)

    На этом шаге мы рассмотрим еще один пример использования делегатов.

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace pr171_1
{
    // Объявление делегата: 
    delegate int Method(int n);

    // Класс с индексатором: 
    class MyClass {
        // Закрытое целочисленное поле: 
        private int num;
        // Конструктор с целочисленным аргументом: 
        public MyClass(int n) { 
            num = n;
        }
        // Первый закрытый метод: 
        private int first(int n) { 
            return n + num;
        }
        // Второй закрытый метод: 
        private int second(int n) { 
            return n - num;
        }
        // Третий закрытый метод: 
        private int third(int n) { 
            return n * num;
        }
        // Индексатор с целочисленным индексом.
        // Результат - ссылка на экземпляр делегата: 
        public Method this[int k] {
            // Аксессор для считывания значения: 
            get {
                switch(k) { 
                    case 0:
                        return first; 
                    case 1:
                        return second; 
                    default:
                        return third;
                }
            }
        }
    }

    // Класс с главным методом:
    class Program
    {
        // Главный метод:
        static void Main()
        {
            // Переменная: 
            int x = 12;
            // Создание объекта:
            MyClass obj = new MyClass(4);
            // Индексирование объекта: 
            for (int k = 0; k <= 2; k++)
            {
                Console.WriteLine("obj[{0}]({1}) = {2}", k, x, obj[k](x));
            }
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

    При выполнении программы получим следующий результат:


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

    Делегат Method объявляется командой

  delegate int Method(int n);
и соответствует методам с одним целочисленным аргументом и целочисленным результатом. В классе MyClass мы описываем закрытое целочисленное поле num, значение которому присваивается при создании объекта. Еще в классе описаны три закрытых метода. Метод first() возвращает в качестве результата сумму значения своего аргумента и поля num. Метод second() результатом возвращает разность аргумента и поля num. Метод third() возвращает результатом произведение значений аргумента и поля num. Еще раз подчеркнем, что все три метода закрытые, поэтому прямого доступа к ним вне пределов класса нет. Но в классе описан индексатор с get-аксессором. Тип результата, возвращаемого аксессором, указан как Method. Это означает, что при индексировании объекта мы результатом получаем ссылку на экземпляр делегата Method. Но фактически это ссылка на метод, который соответствует параметрам делегата Method.

    Индексатор описан так, что если индекс равен 0, то результатом возвращается значение first (ссылка на метод first() индексируемого объекта). Если индекс равен 1, то результатом возвращается значение second (ссылка на метод second() индексируемого объекта). При всех других значениях индекса результатом возвращается ссылка third на метод third() индексируемого объекта.


В описании аксессора указано, что результатом он возвращает значение типа Method. Что это означает? Это значит, что результатом аксессора является ссылка на экземпляр делегата Method. При вызове аксессора для записи результата выделяется переменная (типа Method). Эта переменная может ссылаться на экземпляр делегата. Фактическим значением аксессор возвращает ссылку на метод. Получается, что переменной типа Method присваивается ссылка на метод. В этом случае, как мы помним, автоматически создается экземпляр делегата, который ссылается на метод. Ссылка на экземпляр делегата записывается в переменную, выделенную для запоминания результата аксессора.

    В главном методе программы мы проверяем работу индексатора. Для этого командой

  MyClass obj = new MyClass(4);
создаем объект obj класса MyClass. Целочисленное поле num этого объекта равно 4 (аргумент конструктора). Далее для переменной x со значением 12 в цикле при фиксированном значении переменной k (изменяется в пределах от 0 до 2 включительно) вычисляется значение выражения obj[k](x). Несложно заметить, что в этом случае с аргументом x из объекта obj последовательно вызываются методы first(), second() и third().


Таким образом, выражения вида obj[k] мы можем отождествлять с именем метода.

    На следующем шаге мы закончим изучение этого вопроса.




Предыдущий шаг Содержание Следующий шаг