Функциональный тип. Делегаты
Слово делегат ( 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")
}
}