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

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

    Еще один небольшой пример иллюстрирует особенности реализации ссылок на методы объектов. Рассмотрим программный код, представленный ниже.

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

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

    // Класс: 
    class MyClass {
        // Закрытое целочисленное поле: 
        private int number;
        // Конструктор с одним аргументом: 
        public MyClass(int n) {
            // Присваивание значения полю: 
            set(n);
        }
        // Метод для присваивания значения полю: 
        public void set(int n) {
            // Присваивание значения полю: 
            number = n;
        }
        // Переопределение метода ToString(): 
        public override string ToString() { 
            return "Поле number = " + number;
        }
    }

    // Класс с главным методом: 
    class Program
    {
        // Главный метод:
        static void Main()
        {
            // Создание объекта:
            MyClass A = new MyClass(100);
            // Объектная переменная ссылается 
            // на ранее созданный объект:
            MyClass B = A;
            // Переменной типа делегата значением присваивается 
            // ссылка на метод объекта:
            MyDelegate apply = A.set;
            // Переменной присваивается ссылка на новый объект:
            A = new MyClass(200);
            // Проверка значений полей объектов:
            Console.WriteLine(A);
            Console.WriteLine(B);
            // Вызов экземпляра делегата: 
            apply(300);
            Console.WriteLine();
            // Проверка значений полей объектов:
            Console.WriteLine(A);
            Console.WriteLine(B);
            // Задержка:
            Console.ReadLine();
        }
    }
}
Архив проекта можно взять здесь.

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


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

    В программе объявляется делегат MyDelegate, соответствующий методам, имеющим целочисленный аргумент и не возвращающим результат. Также мы используем класс MyClass. В классе описано закрытое целочисленное поле number. Значение полю присваивается при создании объекта. Не возвращающий результат метод set() получает при вызове целочисленный аргумент, значение которого присваивается полю number. Также в классе переопределен метод ToString(), возвращающий результатом текстовую строку со значением поля number объекта.

    В главном методе мы с помощью команды

  MyClass A = new MyClass(100);
создаем объект, значение поля number которого равно 100. После выполнения команды
  MyClass B = A;
переменные A и B ссылаются на один и тот же объект. При выполнении команды
  MyDelegate apply = A.set;
создается экземпляр делегата MyDelegate, он содержит ссылку на метод set() объекта A, а ссылка на экземпляр делегата записывается в переменную apply. После этого с помощью команды
  A = new MyClass(200);
создается новый объект (значение поля number этого объекта равно 200) и ссылка на него записывается в переменную A. Получается такая ситуация: при присваивании значения переменной apply переменная A ссылалась на один объект, а теперь она ссылается на другой объект. Возникает естественный вопрос: на метод set() какого объекта будет ссылаться (через экземпляр делегата) переменная apply? Ответ следующий: переменная apply ссылается на метод того объекта, на который ссылалась переменная A на момент присваивания значения переменной apply. Другими словами, при выполнении команды
  MyDelegate apply = A.set;
создается ссылка на метод set() объекта, на который ссылается переменная A (напомним, что переменная B ссылается на тот же объект). И даже если затем переменная A получит новое значение и будет ссылаться на другой объект, переменная apply будет связана все с тем же объектом. Для нее ничего не меняется.

    Проверить справедливость данного утверждения легко. У нас есть две переменные: переменная A ссылается на новый объект (значение поля 200), а переменная B ссылается на исходный объект (значение поля 100). Сначала проверяем значения полей объектов (команды

  Console.WriteLine(A);
и
  Console.WriteLine(B);
), а затем командой
  apply(300);
вызываем экземпляр делегата, связанного с методом set() объекта, на который ссылается переменная B, и снова проверяем значения полей объектов. Как видим, изменилось поле того объекта, на который ссылается переменная B.

    Со следующего шага мы начнем изучение анонимных методов.




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