Что такое делегаты и события в C#
Что проверяют
Понимаете ли вы, что событие это ограничение над делегатом, и знаете ли про утечки подписок.
Как отвечать
Делегат это типобезопасная ссылка на метод. Он описывает сигнатуру, а переменная такого типа хранит конкретный метод и может быть вызвана.
delegate int Transform(int x);
Transform t = x => x * 2;На практике собственные типы делегатов объявляют редко: есть готовые обобщённые для действия без результата, функции с результатом и предиката.
Делегат многоадресный: к нему можно присоединить несколько методов, и при вызове выполнятся все по очереди. Отсюда и вырастают события.
Событие это не отдельная сущность, а ограниченный доступ к делегату. Снаружи класса можно только подписаться и отписаться. Вызвать событие или заменить весь список подписчиков присваиванием может только сам класс.
Зачем это ограничение: без него любой посторонний код мог бы присваиванием стереть всех подписчиков или вызвать событие от имени объекта. Именно поэтому поле делегата не выставляют наружу, а объявляют событие.
Практические моменты, которые и отличают знающего:
- утечка через подписки. Издатель хранит ссылки на подписчиков, поэтому подписчик не будет собран сборщиком, пока не отпишется. Долгоживущий издатель и короткоживущие подписчики это классический источник утечек. Отписка обязательна;
- безопасный вызов: у события без подписчиков значение пустое, поэтому вызов делают через условный оператор. Он же берёт значение один раз, что снимает гонку между проверкой и вызовом;
- исключение у одного подписчика прерывает всю цепочку, и остальные не выполнятся;
- соглашение о сигнатуре: отправитель и объект с данными события. Следовать ему стоит ради предсказуемости.
Полезно упомянуть, что для потоков событий во времени часто удобнее реактивные расширения или каналы, а обычные события хороши для точечных уведомлений.
Где спотыкаются
Выставляют наружу поле делегата вместо события.
Не отписываются и получают утечку.
Вызывают событие без проверки на отсутствие подписчиков.
Не учитывают, что исключение у одного подписчика прервёт остальных.