ПрограммированиеVB.NET разработчик

Как в Visual Basic реализовать работу с событиями и делегатами, и чем отличается сценарий их использования для стандартных и пользовательских событий?

Проходите собеседования с ИИ помощником Hintsage

Ответ.

В Visual Basic (VB.NET) делегаты представляют собой тип, содержащий ссылку на метод с определённой сигнатурой, и служат основой для обработки событий. События построены на делегатах, позволяя объектам уведомлять других о произошедших изменениях.

Для стандартных событий используются уже определённые делегаты, например, EventHandler, а для пользовательских — можно определить собственный делегат с нужной сигнатурой:

'Объявление пользовательского делегата и события Public Delegate Sub ChangedEventHandler(sender As Object, e As EventArgs) Public Event Changed As ChangedEventHandler 'Использование события Public Sub OnChanged() RaiseEvent Changed(Me, EventArgs.Empty) End Sub

Тонкости:

  • Событие можно вызвать только внутри того класса, где оно объявлено;
  • Делегаты можно комбинировать, создать цепочку вызовов;
  • Несоблюдение правильной сигнатуры приводит к ошибкам компиляции.

Вопрос с подвохом.

Почему событие в Visual Basic нельзя вызвать вне класса, даже если оно объявлено как Public?

Ответ: Несмотря на модификатор доступа Public, событие можно только "подписать" или "отписать" извне класса, но вызвать (RaiseEvent) можно только в пределах класса — это специфика языка, обеспечивающая инкапсуляцию и контроль над рассылкой событий. Например:

Public Class Foo Public Event MyEvent() End Class Dim f As New Foo() ' Так нельзя: f.RaiseEvent MyEvent() — компилятор не даст этого сделать.

Примеры реальных ошибок из-за незнания тонкостей темы.


История

Проект Windows Forms: Разработчик пытался вызвать событие "DataUpdated" извне класса данных, чтобы обновить UI. Не удалось, событие не было обработано, пришлось рефакторить архитектуру, переделывать логику из-за неправильного понимания области видимости события.


История

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


История

Плагин к 1С: Разработчики использовали FieldInfo.SetValue для имитации вызова RaiseEvent. Это вызвало рассогласование состояния интерфейса и креш при обновлении сборки.