Привет, мир! :)

Как дела?? Надеюсь, вы отлично провели время в канун Рождества и Нового года. В основном из-за этих праздников я не писал здесь рассказов.

Но что ж, эти праздники уже прошли, так что… приступим к делу!

В прошлом рассказе я писал о цели Реализовать поток программы. Теперь я напишу о четвертой цели: Создание и реализация событий и обратных вызовов!

Понимание делегатов

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

Пример кода:

В приведенном выше примере кода ссылка на метод делегата «перезапущена», поскольку метод напрямую назначается делегату, перезаписывая предыдущую ссылку на метод.

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

Пример кода:

Использование лямбда-выражений

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

Наконец, вы можете определить несколько операторов внутри лямбда-выражения, просто вставив фигурные скобки вокруг этих операторов.

Пример кода:

В приведенном выше примере кода мы определяем делегат многоадресной рассылки, используя лямбда-выражения, а также определяем лямбда-выражение с двумя операторами внутри него.

Использование событий

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

Например, когда вы разрабатываете настольное приложение с использованием WPF, вы можете добавить кнопку на страницу и добавить обработчик событий к событию щелчка. Когда кнопка получает щелчок, вызываются методы, подписанные на ее событие!

Пример кода:

В приведенном выше коде определено действие OnChange. Действие определяет подпись метода делегата без возвращаемого типа.

При таком подходе к реализации событий есть две проблемы:

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

Но не бойся. На помощь приходит ключевое слово event!

Его использование в основном устраняет оба этих недостатка. Это не позволяет пользователям класса перезаписывать ссылки на методы делегата. Кроме того, он устраняет вторую проблему, ограничивая вызов делегата кодом класса.

Последнее, что мы должны сделать перед тем, как перейти к реализации событий в .NET, - это переключить тип делегата Action на EventHandler или EventHandler ‹T›, где T - это тип аргументов события. Это в основном соответствует соглашениям .NET (если вы посмотрите на свои события Button clicks, вы заметите, что они следуют тем же соглашениям).

Круто, а? Давайте посмотрим на пример кода, чтобы было понятнее. :)

Пример кода:

В приведенном выше коде событие определяется с использованием ссылочного типа MyArgs в качестве аргумента события EventHandler. Затем мы добавляем ссылки на методы (в нашем случае лямбда-выражения) в событие OnChange. Наконец, мы поднимаем событие для всех подписчиков.

Мы также можем создавать собственные средства доступа для делегата для добавления и удаления подписчиков. Чтобы обеспечить потокобезопасность операции, используется ключевое слово lock (дополнительную информацию о ключевом слове lock см. В Objective 1.2 Story).

Пример кода:

Обработка исключений при вызове подписчиков

Что, если один из вызовов подписчика вызывает исключение? Выполнит ли он все, кроме неисправного?

Ответ: он будет выполнять всех подписчиков в списке вызовов, пока не возникнет исключение, завершающее вызов.

Мы можем решить эту проблему, реализовав обработку ошибок внутри метода, который вызывает событие для всех подписчиков (в нашем случае метод Raise). Мы можем получить доступ к подписчикам с помощью метода GetInvocationList.

Пример кода:

На данный момент это все! :) Надеюсь, что Story будет вам полезен при изучении Задачи 1.4. В следующем рассказе я напишу о Задаче 1.5: Реализовать обработку исключений.

Увидимся!

PS: Если вы найдете эту историю полезной, я приглашаю вас нажать кнопку «Хлопать». Также буду рад видеть Вас в качестве моего нового последователя!