|
Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет: Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.
Как активировать код? |
Интерфейсы, делегаты, события в 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#
Рассылка сообщений с помощью делегата
Чтобы любые объекты могли обмениваться информацией, они должны разговаривать на одном языке. В случае объектно-ориентированного программирования таким условием является одинаковый прототип функций, определяемый делегатом. Многоадресная работа делегата удобна тем, что можно послать одинаковое сообщение сразу нескольким объектам, функции которых зарегистрированы в списке делегата как обработчики этого сообщения. Список делегата можно назвать по-разному:
- список вызываемых функций,
- список обработчиков,
- список адресатов,
- список получателей и т.д.
Напомним, что если список адресатов пуст, то самого объекта-делегата не существует и ссылка на него имеет значение 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 не выполняет роль хранителя ссылки на обычный экземпляр класса или структуры, а предназначено для создания механизма адресации функций.


