Найти в Дзене
.Net Review

Разница между Событиями и Делегатами. Разбираем на примере

Оглавление

Пред нами стоит один из часто задаваемых на собеседовании вопросов — Чем различаются Делегаты от Событий? Подробнее об этом в этой статье.

Для начала стоит разобраться с элементами рассматриваемой области, начнем с Делегатов. Говоря самыми приближенными и простыми терминами, можно сказать,что делегат это переменная которая может содержать в себе функцию(метод) которую мы вызываем с помощью нашей переменной-делегата. Одна из проблем понимания делегатов, как явления в языке программирования стоит упомянуть, что такие понятия как Классы-Делегаты и Объекты-Делегаты часто называют просто Делегатами, тем самым смешивая терминологию(делать этого не стоит, но в порыве объяснения чего либо с ними (делегатами) связанного — разрешается).

Объяснения на примере

Итак, Класс-делегат является самым что ни на есть обычным классом Delegate унаследованным от Object и содержит в себе следующие свойства и методы которые чаще всего применимы на практике:

  1. Target — свойство, которое хранит ссылку на экземпляр объекта в котором содержится метод сообщенный с делегатом, а если метод static то значение равно null.
  2. Method — свойство, которое хранит имя последнего метода сообщенного с делегатом из класса в котором объявлена переменная-делегат.
  3. Combine — метод объединяющий списки вызовов двух делегатов.
  4. GetInvocationList — метод возвращающий массив делегатов , представляющий список вызовов текущего делегата.(массив методов простыми словами).
Обьявление Типа-делегата и Объекта-делегата
Обьявление Типа-делегата и Объекта-делегата

В свою очередь события выглядят вот так (правда очень похоже).

Обьявление Типа-делегата и Объекта-События(или просто События)
Обьявление Типа-делегата и Объекта-События(или просто События)

Ну и живой пример класса в котором используется объект-делегат. В данном классе мы создаем объект-делегат makeNoise и связываем с ним метод MakeFlash. Следует заметить что данный класс так же имеет метод Fire который и будет использован конечным пользователем.

Класс Weapon содержащий делегат
Класс Weapon содержащий делегат

Класс Program в котором реализована основная логика программы. Здесь мы создаем два экземпляра класса Weapon(gun и cannon) и после этого сообщаем с полями-делегатами(makeNoise) методы GunBlast и CannonBlast соответсвенно. А после вызываем метод Fire который в своей реализации "дергает" объект-делегат и вызывает все сообщенные с ним методы.

Класс Program
Класс Program

После работы программы консоль выглядит следующим образом. Произошел вызов совмещенных с полем-делегатом методов из метода Main а так же были вызваны те методы которые были переданы объекту делегату в классе Weapon.

Консольный результат
Консольный результат

Но что же будет если использовать ключевое слово event?

Поле-событие которое было делегатом в предшествующих примерах
Поле-событие которое было делегатом в предшествующих примерах

А ничего программа будет выполняться как и прежде и результат будет тот же, НО есть один нюанс, теперь мы не можем непосредственно у makeNoise вызвать такие методы как Invoke, GetInvocationList, и не получиться обратиться к полям Method и Target. В этом и заключается основное отличие делегатов от событий — вторые боле "приватные", "защищенные", они не имеют никаких методов и полей, мы лишь можем применить к ним операции += и -= которые позволяют связывать и убирать методы из списка вызовов.

Итог

Из всего вышесказанного можно выделить следующее:

  1. События можно заменить делегатами и ничего не сломается;
  2. События являются приватно-ориентированной моделью делегатов.

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

Наука
7 млн интересуются