Я не вижу преимуществ использования событий перед делегатами, кроме синтаксического сахара. Возможно, я неправильно понимаю, но кажется, что событие - это просто заполнитель для делегата.
Не могли бы вы объяснить мне различия и когда их использовать? Какие преимущества и недостатки? Наш код сильно связан с событиями, и я хочу разобраться в этом.
Когда бы вы использовали делегатов вместо событий и наоборот? Пожалуйста, укажите свой реальный опыт работы с обоими, скажем, в производственном коде.
Ответы:
С технической точки зрения другие ответы касались различий.
С точки зрения семантики события - это действия, вызываемые объектом при выполнении определенных условий. Например, у моего класса Stock есть свойство Limit, и оно вызывает событие, когда цена акций достигает Limit. Это уведомление делается через событие. Независимо от того, действительно ли кто-нибудь заботится об этом событии и подписывается на него, класс-владелец не занимается.
Делегат - это более общий термин для описания конструкции, аналогичной указателю в терминах C / C ++. Все делегаты в .Net являются делегатами многоадресной рассылки. С точки зрения семантики они обычно используются как своего рода ввод. В частности, они являются прекрасным способом реализации паттерна стратегии . Например, если я хочу отсортировать список объектов, я могу предоставить методу стратегию Comparator, чтобы сообщить реализации, как сравнивать два объекта.
Я использовал два метода в производственном коде. Тонны моих объектов данных уведомляют, когда выполняются определенные свойства. Самый простой пример: всякий раз, когда свойство изменяется, возникает событие PropertyChanged (см. Интерфейс INotifyPropertyChanged). Я использовал делегаты в коде, чтобы предоставить различные стратегии преобразования определенных объектов в строку. Этот конкретный пример представлял собой прославленный список реализаций ToString () для определенного типа объекта, чтобы отображать его пользователям.
источник
Ключевое слово
event
является модификатором области для делегатов многоадресной рассылки. Практические различия между этим и простым объявлением многоадресного делегата заключаются в следующем:event
в интерфейсе.public event
).Собственно интерес, вы можете применить
+
и-
для многоадресной рассылки делегатов, и это является основой+=
и-=
синтаксис для назначения комбинации делегатов на события. Эти три фрагмента эквивалентны:Второй образец, иллюстрирующий как прямое назначение, так и комбинированное назначение.
Пример третий: более знакомый синтаксис. Вы, наверное, знакомы с назначением null для удаления всех обработчиков.
Как и свойства, события имеют полный синтаксис, который никто никогда не использует. Это:
... делает точно так же , как это:
Методы добавления и удаления более заметны в довольно неестественном синтаксисе, который использует VB.NET (без перегрузок операторов).
источник
События - это синтаксический сахар. Они восхитительны. Когда я вижу событие, я знаю, что делать. Когда я вижу делегата, я не уверен.
Комбинирование событий с интерфейсами (больше сахара) делает вас вкусной закуской. Делегаты и чисто виртуальные абстрактные классы гораздо менее аппетитны.
источник
События отмечены как таковые в метаданных. Это позволяет таким вещам, как Windows Forms или конструкторы ASP.NET, отличать события от простых свойств типа делегата и обеспечивать для них соответствующую поддержку (в частности, показывая их на вкладке «События» в окне «Свойства»).
Еще одно отличие от свойства типа делегата состоит в том, что пользователи могут только добавлять и удалять обработчики событий, тогда как со свойством типа делегата они могут устанавливать значение:
Это помогает изолировать подписчиков на события: я могу добавить свой обработчик к событию, а вы можете добавить свой обработчик к тому же событию, и вы случайно не перезапишете мой обработчик.
источник
Хотя события обычно реализуются с помощью делегатов многоадресной рассылки, нет требования, чтобы они использовались таким образом. Если класс предоставляет событие, это означает, что класс предоставляет два метода. По сути, их значения:
Наиболее распространенный способ обработки классом события, которое он предоставляет, - это определение делегата многоадресной рассылки и добавление / удаление любых делегатов, которые передаются указанным выше методам, но не требуется, чтобы они работали таким образом. К сожалению, архитектура событий не может делать некоторые вещи, которые сделали бы альтернативные подходы намного чище (например, чтобы метод подписки возвращал MethodInvoker, который будет храниться подписчиком; чтобы отменить подписку на событие, просто вызовите возвращенный метод), поэтому многоадресные делегаты на сегодняшний день являются наиболее распространенным подходом.
источник
чтобы понять различия, вы можете посмотреть эти 2 примера
Пример с делегатами (действие в данном случае - это своего рода делегат, не возвращающий значение)
чтобы использовать делегат, вы должны сделать что-то вроде этого
этот код работает хорошо, но у вас могут быть слабые места.
Например, если я напишу это
с последней строкой кода я переопределил предыдущее поведение только с одним отсутствующим
+
(я использовал+
вместо+=
)Еще одно слабое место в том, что каждый класс, использующий ваш
Animal
класс, может поднять его,RaiseEvent
просто вызвав егоanimal.RaiseEvent()
.Чтобы избежать этих слабых мест, вы можете использовать
events
в C #.Ваш класс Animal изменится таким образом
вызывать события
Отличия:
ноты
EventHandler объявлен как следующий делегат:
он принимает аргументы отправителя (типа Object) и события. Отправитель имеет значение NULL, если он исходит из статических методов.
Вы также можете использовать
EventHAndler
вместо этого этот пример, который используетEventHandler<ArgsSpecial>
обратитесь сюда для документации о EventHandler
источник
Когда я разрабатываю свои собственные API, я определяю делегаты, которые передаются как параметры методам или конструкторам классов:
Predicate
иAction
делегаты передаются в классы общего сбора .Net)Эти делегаты обычно не являются обязательными во время выполнения (т.е. не должны быть
null
).Я стараюсь не использовать события; но там, где я использую события, я использую их для факультативной сигнализации событий нулю, одному или нескольким клиентам, которые могут быть заинтересованы, то есть когда имеет смысл, что класс (например,
System.Windows.Form
класс) должен существовать и запускаться независимо от того, есть ли у какого-либо клиента добавил обработчик событий к своему событию (например, существует событие формы «мышь вниз», но это необязательно, если какой-либо внешний клиент заинтересован в установке обработчика событий на это событие).источник
Хотя у меня нет технических причин для этого, я использую события в коде стиля пользовательского интерфейса, другими словами, на более высоких уровнях кода и использую делегаты для логики, которая лежит глубже в коде. Как я уже сказал, вы можете использовать и то, и другое, но я считаю этот шаблон использования логически обоснованным, как минимум, он помогает документировать типы обратных вызовов и их иерархию.
Изменить: я думаю, что разница в шаблонах использования, которые у меня были, заключалась бы в том, что я считаю вполне приемлемым игнорировать события, они являются крючками / заглушками, если вам нужно знать о событии, слушайте их, если вам все равно событие просто игнорируйте. Вот почему я использую их для пользовательского интерфейса, вроде стиля событий Javascript / Browser. Однако, когда у меня есть делегат, я ДЕЙСТВИТЕЛЬНО ожидаю, что кто-то обработает задачу делегата, и выдаст исключение, если оно не обработано.
источник
Разница между событиями и делегатами намного меньше, чем я думал ... Я только что опубликовал на YouTube супер короткое видео на эту тему: https://www.youtube.com/watch?v=el-kKK-7SBU
Надеюсь это поможет!
источник
источник