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

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

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

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

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

    // Класс с главным методом: 
    class Program
    {
        // Статический метод результатом возвращает ссылку на
        // экземпляр делегата:
        static MyDelegate calculate(int n) {
            // Локальная переменная: 
            int count = 0;
            // Результат реализован через анонимный метод: 
            return delegate() {
                count += n; 
                return count;
            };
        }
        // Главный метод: 
        static void Main()
        {
            // Переменная типа делегата:
            MyDelegate next = calculate(1); 
            for (int i = 1; i <= 5; i++)
            {
                // Вызов экземпляра делегата:
                Console.Write(next() + " ");
            }
            Console.WriteLine();
            // Новое значение переменной типа делегата: 
            next = calculate(3);
            for (int i = 1; i <= 5; i++)
            {
                // Вызов экземпляра делегата:
                Console.Write(next() + " ");
            }
            Console.WriteLine();
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

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


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

    Делегат MyDelegate описан для создания экземпляров, которые могут ссылаться на методы без аргументов, возвращающие целочисленный результат. Еще мы описываем статический метод calculate(), у которого целочисленный аргумент (обозначен как n) и который результатом возвращает ссылку на экземпляр делегата MyDelegate. В теле метода объявлена локальная целочисленная переменная count с начальным нулевым значением. Далее следует return-инструкция и возвращаемым значением указано следующее выражение (после этого выражения в коде метода стоит точка с запятой):

  return delegate() {
                count += n; 
                return count;
            };

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


Тип результата для метода calculate() указан как MyDelegate. Формально это ссылка на экземпляр делегата MyDelegate. При вызове метода calculate() под результат метода выделяется переменная типа делегата MyDelegate. Результатом метод calculate() возвращает анонимный метод, который присваивается переменной, выделенной для записи результата. В итоге создается экземпляр делегата, который ссылается на анонимный метод. Ссылка на этот экземпляр записывается в переменную, выделенную для запоминания результата метода calculate(). Поэтому результатом метода calculate() является ссылка на экземпляр делегата MyDelegate, а этот экземпляр ссылается на упомянутый выше анонимный метод.

    В главном методе программы командой

  MyDelegate next = calculate(1); 
объявляется переменная next типа делегата MyDelegate, и значением ей присваивается результат вызова метода calculate() с аргументом 1. Затем с помощью конструкции цикла несколько раз подряд вычисляется значение выражения next(). И каждый раз мы получаем новое значение (числа 1, 2, 3 и так далее). Почему так происходит? При вызове метода calculate() с аргументом 1 создается локальная переменная count с начальным значением 0. Мы уже знаем, что метод calculate() возвращает результатом анонимный метод, который при вызове каждый раз увеличивает значение переменной count (в данном случае на 1) и это новое значение возвращает как результат. В итоге получается так: переменная next ссылается на экземпляр делегата, который ссылается на анонимный метод, а этот метод содержит ссылку на переменную count, созданную при вызове метода calculate(). После завершения вызова метода calculate() локальная переменная count должна бы удаляться. Но поскольку на эту переменную есть ссылка в анонимном методе, то она "выживает". После первого вызова анонимного метода через переменную next значение переменной count становится равным 1. При втором вызове она становится равной 2 и так далее. Поэтому при вычислении значения выражения next() мы каждый раз получаем новое число (на единицу больше предыдущего).

    После выполнения команды

  next = calculate(3);
в переменную next записывается ссылка на новый экземпляр делегата, ссылающийся на новый анонимный метод, который ссылается на новую локальную переменную count. Она получила начальное значение 0 при вызове метода calculate(). И теперь каждый раз при вычислении значения выражения next() мы получаем новое число, большее предыдущего на 3.

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




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