Функциональный тип. Делегаты

Слово делегат ( delegate ) используется в C# для обозначения хорошо известного понятия, давно употребляемого в языках программирования. Делегат C# задает определение функционального типа (класса) данных. Экземплярами такого класса являются функции. Делегаты языка C# наряду со структурами, перечислениями и интерфейсами представляют задание еще одного частного случая классов. Каждый делегат описывает множество функций с заданной сигнатурой. Каждая функция, или если быть более точным и придерживаться терминологии, принятой в объектно-ориентированном программировании, каждый метод, сигнатура которого совпадает с сигнатурой делегата, может рассматриваться как экземпляр класса, заданного делегатом. Синтаксис объявления делегата имеет следующий вид:

[<спецификатор доступа>] delegate <тип результата > <имя класса> (<список аргументов>);

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

Спецификатор доступа может быть, как обычно, опущен. Где следует размещать объявление делегата? Как и у всякого класса, есть две возможности:

1. непосредственно в пространстве имен, наряду с объявлениями других классов, структур, интерфейсов;

2. внутри другого класса, наряду с объявлениями методов и свойств. Такое объявление рассматривается как объявление вложенного класса.

Так же, как и интерфейсы C#, делегаты не задают реализации. Фактически между некоторыми классами и делегатом заключается контракт на реализацию делегата. Классы, согласные с контрактом, могут объявить у себя статические или динамические функции, сигнатура которых совпадает с сигнатурой делегата. Далее они могут создать экземпляр делегата, присвоив ему в качестве значения функцию, удовлетворяющую контракт. Заметьте, контракт является жестким: не допускается ситуация, при которой у делегата тип параметра - object, а у функции, связываемой с экземпляром, соответствующий параметр имеет тип int, хотя и согласованный с типом object, но не совпадающий с ним.

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

Классы с событиями

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

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

Для того, чтобы работать с некоторым событием нам нужно:

1) Объявить делегат, задающий сигнатуру определенного метода(Выполнимого при наступлении события);

2) Объявить событие типа делегата (Типом будет имя нашего делегата);

3) Зарегистрировать (подписать) на событие некоторый метод, который соответствует сигнатуре делегата;

4) При определенных условиях выполнить событие;

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

event делегат_события имя_события

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

class Program

{ ClassCounter Counter = new ClassCounter();

Handler_I Handler1 = new Handler_I();

Handler_II Handler2 = new Handler_II();

// Подписались на событие

Counter.onCount += Handler1.Message;

Counter.onCount += Handler2.Message;

}

// Это класс в котором производится счет

class ClassCounter

{

public delegate void MethodContainer(); // Объявление делегата

public event MethodContainer onCount; // Событие OnCount c типом делегата MethodContainer.

public void Count()

{

for(int i = 0; i<100; i++)

if (i == 71) onCount(); // запускаем событие

}

}

//Это класс, реагирующий на событие (счет равен 71) записью строки в консоли.

class Handler_I

{

public void Message()

{

Console.WriteLine("Пора действовать, ведь уже 71!");

}

}

class Handler_II

{

public void Message()

{

Console.WriteLine("Точно, уже 71")

}

}

Наши рекомендации