Разницу между событием и делегатом в C# довольно сложно объяснить.
Делегат - это тип, который может содержать список функций, соответствующих спецификации. Поэтому
public EventHandler<bool> SomeEvent;
объявляет публикуемое c поле SomeEvent
.
. Код клиента может добавлять функции в этот список и удалять их, что является разумным решением. Но клиентский код может также вызывать функции в списке, которые нам не нужны. Это должно быть делом класса SomeService
.
Поэтому мы хотим, чтобы операции add и remove (+ = и - =) были опубликованы c, а вызовы были приватными.
Это именно то, что делает ключевое слово события.
public event EventHandler<bool> SomeEvent;
Приведенный выше код фактически создает три элемента в классе:
- Закрытое поле типа EventHandler
- Метод publi c с именем add_SomeEvent
- Метод publi c с именем remove_SomeEvent
Вызов SomeEvent + = или SomeEvent- = отображается на эти последние два.
Вот как это выглядит в ILDASM:

Теперь интерфейс может указывать только методы (свойство, являющееся пара методов), поэтому, когда мы объявляем событие в интерфейсе, это означает, что класс, реализующий интерфейс, должен предоставить методы добавления и удаления (2 и 3 выше). На самом деле он не требует, чтобы класс предоставлял приватное поле.
Однако наиболее распространенный способ реализации события из интерфейса - это объявление его таким же образом, что дает нам два метода и поле, которое является бонусом (что касается интерфейса).
Можно (хотя и не так часто) вручную реализовывать событие, то есть два пишут методы добавления и удаления для нас самих и хранить фактический делегат каким-либо иным способом, кроме простого поля. Обычно это делается либо для экономии памяти, когда в классе имеется большое количество событий, либо для пересылки события, которое будет управляться другим событием в другом классе.