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

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

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

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

namespace pr174_1
{
    // Объявление первого делегата: 
    delegate int Alpha(int n);
    
    // Объявление второго делегата: 
    delegate void Bravo(string t);

    // Класс: 
    class MyClass {
        // Открытое целочисленное поле: 
        public int number;
        // Конструктор: 
        public MyClass(int n) {
            number = n; // Значение поля
        }
        // Поле, являющееся ссылкой на экземпляр делегата: 
        public Alpha method;
    }

    // Класс с главным методом: 
    class Program
    {
        // Главный метод:
        static void Main()
        {
            // Создание объектов:
            MyClass A = new MyClass(100);
            MyClass B = new MyClass(200);
            // Полю объекта значением присваивается 
            // анонимный метод:
            A.method = delegate(int n) {
                return A.number + n;
            };
            // Полю объекта значением присваивается 
            // анонимный метод:
            B.method = delegate(int n) {
                return B.number - n;
            };
            // Целочисленная переменная: 
            int x = 80;
            // Вызов экземпляра делегата:
            Console.WriteLine("A.method({0}) = {1}", x, A.method(x));
            // Присваивание нового значения полю:
            A.number = 300;
            // Вызов экземпляров делегата:
            Console.WriteLine("A.method({0}) = {1}", x, A.method(x));
            Console.WriteLine("B.method({0}) = {1}", x, B.method(x));
            // Объявление переменной типа делегата:
            Bravo show;
            // Присваивание переменной анонимного метода: 
            show = delegate(string t) {
                Console.WriteLine("Teкст: \"{0}\"", t);
            };
            // Вызов экземпляра делегата: 
            show("Bravo");
            // Присваивание переменной анонимного метода:  
            show = delegate(string t) {
                for(int k = 0; k < t.Length; k++) {
                    Console.Write("|" + t[k]);
                }
                Console.WriteLine("|");
            };
            // Вызов экземпляра делегата: 
            show("Bravo");
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

    Ниже представлен результат выполнения программы:


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

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

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


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

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

  MyClass A = new MyClass(100);
и
  MyClass B = new MyClass(200);
создаются объекты A и B класса MyClass. У объекта A поле number равно 100, а у объекта B поле number равно 200.

    Далее полю method каждого из объектов значением присваивается анонимный метод. Для объекта A команда присваивания следующая:

  A.method = delegate(int n) {
                return A.number + n;
            };

    Полю method объекта A присваивается в качестве значения конструкция, которая начинается с ключевого слова delegate и заканчивается закрывающей фигурной скобкой, после которой стоит точка с запятой. То есть значением присваивается такое выражение:

  delegate(int n) {
                return A.number + n;
            };

    Это и есть описание анонимного метода. У него один целочисленный аргумент (обозначен как n), а результатом метод возвращает значение выражения A.number+n (сумма значения поля number объекта A и аргумента метода n). Именно такой код будет выполняться при вызове экземпляра делегата, на который ссылается поле method объекта A.

    Полю method объекта B также присваивается анонимный метод, но немного другой. Соответствующая команда выглядит следующим образом:

  B.method = delegate(int n) {
                return B.number - n;
            };

    В данном случае анонимный метод определен таким образом, что результатом он возвращает разность значения поля number объекта B и аргумента метода n.

    Работу анонимных методов проверяем, вызывая соответствующие экземпляры делегатов командами A.method(x)) и B.method(x) (при значении 80 для переменной x). Легко убедиться, что результат вычисляется в соответствии с тем, как мы определили анонимные методы.


Обратите внимание на одно обстоятельство. Объекты A и B созданы на основе класса MyClass, поэтому у каждого из объектов есть поле method. Поскольку поле является ссылкой на экземпляр делегата, мы можем его вызывать как метод. Создается иллюзия, что мы имеем дело с методом. Но этот "метод" у разных объектов разный, хотя объекты относятся к одному классу. Фактически с помощью анонимных методов мы можем менять код, связанный с полем method, таким же образом, как мы меняем значение для числовых полей.

    Также в главном методе командой

  Bravo show;
объявляется переменная show с типом Bravo (делегат). Значением такой переменной можно присвоить ссылку на метод, принимающий текстовый аргумент и не возвращающий результат. Сначала значение переменной show присваивается такой командой:
  show = delegate(string t) {
                Console.WriteLine("Teкст: \"{0}\"", t);
            };

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

  show("Bravo");
через переменную show вызываем экземпляр делегата и проверяем работу анонимного метода. Затем переменной show присваивается в качестве значения новый анонимный метод, как показано ниже:
 show = delegate(string t) {
                for(int k = 0; k < t.Length; k++) {
                    Console.Write("|" + t[k]);
                }
                Console.WriteLine("|");
            };

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

  show("Bravo");
убеждаемся в том, что все происходит так, как описано в анонимном методе.


Присваивая переменной show в качестве значения различные анонимные методы, мы создаем впечатление, что имеем дело с методом, программный код которого меняется по мере выполнения программы.

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




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