Ответ
По умолчанию событие в C# — это обёртка над multicast-делегатом. При вызове события все подписанные обработчики вызываются последовательно в порядке их добавления через оператор +=. Если у события нет подписчиков, его вызов через ?.Invoke() безопасно возвращает null и ничего не происходит.
Ключевые особенности:
- Порядок вызова: Обработчики вызываются в порядке подписки (FIFO).
- Исключения: Если один обработчик выбрасывает исключение, последующие обработчики в цепочке не выполняются. Это критично для надёжных систем.
- Потокобезопасность: Операции
+=и-=являются атомарными (потокобезопасными), но конкурентная подписка и вызов события требуют дополнительной синхронизации. - Утечки памяти: Классическая проблема — удержание в памяти объектов-подписчиков. Необходима явная отписка (
-=) перед удалением подписчика.
Пример стандартного использования:
public class Publisher
{
public event EventHandler<EventArgs> OnDataProcessed;
public void ProcessData()
{
// Логика обработки...
OnDataProcessed?.Invoke(this, EventArgs.Empty); // Вызов всех подписчиков
}
}
public class Subscriber
{
public void Subscribe(Publisher pub)
{
pub.OnDataProcessed += HandleNotification;
}
private void HandleNotification(object sender, EventArgs e)
{
Console.WriteLine("Данные обработаны.");
}
}
Кастомное поведение (add/remove аксессоры): Для реализации собственной логики подписки (например, логирования, гарантированного вызова всех обработчиков или weak references) можно переопределить аксессоры add и remove:
private EventHandler _customEvent;
public event EventHandler CustomEvent
{
add
{
Console.WriteLine($"Добавлен обработчик: {value.Method.Name}");
_customEvent += value;
}
remove
{
Console.WriteLine($"Удалён обработчик: {value.Method.Name}");
_customEvent -= value;
}
}