Опубликован: 25.03.2010 | Доступ: свободный | Студентов: 1447 / 158 | Оценка: 4.31 / 4.00 | Длительность: 25:42:00
Лекция 10:

Интерфейсы, делегаты, события в C#

Методы Combine() и Remove()

Это статические методы, способные получать новый делегат как объединение списков двух делегатов одного и того же типа, или получать новый делегат с усеченным списком при тех же условиях. Методы могут использоваться вместо перегруженных операций ' += ' или ' -= ' при последовательном изменении списка одиночными функциями по синтаксису

MyDelegate del;
            del = new MyDelegate(obj.Handler1);
            del += new MyDelegate(obj.Handler2);
    
            // Или
            del = new MyDelegate(obj.Handler1);
            del = (MyDelegate)Delegate.Combine(del, 
              new MyDelegate(obj.Handler2));
using System;
    
namespace Test
{
    class Handler
    {
        // Функции
        public void Handler1()
        {
            Console.WriteLine("Вызов Handler1()");
        }
    
        public void Handler2()
        {
            Console.WriteLine("Вызов Handler2()");
        }
    }
    
    // Вызывающая сторона
    class MyClass
    {
        public static string Title = "Применение Combine() и Remove()";
    
        // Объявляем делегат как член класса
        delegate void MyDelegate();
    
        public MyClass()
        {
            // Создаем объект
            Handler obj=new Handler();
    
            // Формируем список объекта-делегата из 2 вызовов
            MyDelegate del1 = new MyDelegate(obj.Handler1);
            del1 += new MyDelegate(obj.Handler1);
    
            // Еще один делегат того же типа из 3 вызовов
            MyDelegate del2 = new MyDelegate(obj.Handler2);
            del2 += obj.Handler2;   // Упрощенный синтаксис
            del2 = del2 + obj.Handler2; // То же самое
    
            // Новый делегат из 5 вызовов 
            MyDelegate del3 = (MyDelegate)Delegate.Combine(del1, del2);
    
            // Вызываем 5 функций
            del3();
            Console.WriteLine();
    
            // Вновь формируем делегаты
            del1 = new MyDelegate(obj.Handler1);
            del1 += obj.Handler2;
    
            // Усекаем первый список вторым 
            del2 = (MyDelegate)Delegate.Remove(del3, del1);
    
            // Вызываем оставшиеся 3 функции
            del2();
        }
    }
    
    // Запуск
    class Program
    {
        static void Main()
        {
            // Настройка консоли
            Console.Title = MyClass.Title;
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
            Console.WindowWidth = 33;
            Console.WindowHeight = 10;
    
            new MyClass();// Исполняем
    
            Console.ReadLine();
        }
    }
}
Листинг 10.16 . Применение методов Combine() и Remove()

События в C#

Рассылка сообщений с помощью делегата

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

  1. список вызываемых функций,
  2. список обработчиков,
  3. список адресатов,
  4. список получателей и т.д.

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

Вот пример однонаправленной рассылки сообщения

using System;
    
namespace Test
{
    // Образец сообщения определяется делегатом
    delegate void Message(string message);
    
    // Источник сообщения
    class SourceMessage
    {
        // Общедоступное поле ссылки на объект-делегат,
        // который наполнится указателями
        // на функции в классах-получателях 
        public Message mail;
    
        // Необязательное поле с рассылаемым сообщением
        public string message;
    
        // Разослать сообщение - функция диспетчеризации
        public void DispatchMessage(string mess)
        {
            // Сохраняем внешнее сообщение во внутреннем поле
            message = mess;
    
            // Инициируем рассылку сообщения всем, 
            // кто зарегистрировался в объекте-делегате
            if (mail != null)   // Если не пустой делегат
                mail(mess);
        }
    }
    
    // Получатель сообщения
    class Addressee1
    {
        // Функции
        public void Handler(string message)
        {
            Console.WriteLine("Addressee1 получил:"
                + "\n\t\"{0}\"", message);
        }
    }
    
    // Получатель сообщения
    class Addressee2
    {
        // Функции
        public void Handler(string message)
        {
            Console.WriteLine("Addressee2 получил:"
                + "\n\t\"{0}\"", message);
        }
    }
    
    // Вызывающая сторона
    class MyClass
    {
        static public string Title = "Рассылка 
    сообщений делегатом";
    
        public MyClass()
        {
            // Создаем объекты источника и получателей сообщения
            SourceMessage source = new SourceMessage();
            Addressee1 obj1 = new Addressee1();
            Addressee2 obj2 = new Addressee2();
    
            // Формируем список вызовов объекта-делегата
            source.mail += new Message(obj1.Handler);
            source.mail += new Message(obj2.Handler);
    
            // Рассылаем сообщение напрямую через делегат
            source.mail("Первое сообщение");
            Console.WriteLine();
    
            // Рассылаем сообщение через функцию диспетчеризации
            source.DispatchMessage("Второе сообщение");
        }
    }
    
    // Запуск
    class Program
    {
        static void Main()
        {
            // Настройка консоли
            Console.Title = MyClass.Title;
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
            Console.WindowWidth = 32;
            Console.WindowHeight = 10;
    
            new MyClass();// Исполняем
    
            Console.ReadLine();
        }
    }
}
Листинг 10.17 . Однонаправленная передача сообщений объектам с помощью делегата

Обратите внимание, что при добавлении в делегат первой ссылки на функцию нам не обязательно использовать операцию ' = ', а можно и ' += ', несмотря на то, что делегат еще пустой.


В классе-источнике сообщения SourceMessage мы объявили два общедоступных поля: ссылку mail на объект-делегат и переменную message для хранения сообщения внутри класса. Поле-переменная message для работы программы не нужна, но мы ее ввели просто для того, чтобы сравнить представления в панели Class View.


Если теперь посмотреть на состав класса SourceMessage через панель Class View, то мы не сможем различить две этих переменные - обычные поля, да и только. Но ведь поле mail не выполняет роль хранителя ссылки на обычный экземпляр класса или структуры, а предназначено для создания механизма адресации функций.

Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

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

 

Как активировать код?