Ответ
В C# события — это реализация шаблона наблюдатель (Observer), построенная на основе делегатов. Стандартные события можно разделить по областям применения:
1. События пользовательского интерфейса (WinForms/WPF):
Click,MouseDown,MouseUp,MouseMove— взаимодействие с мышью.KeyDown,KeyUp,KeyPress— обработка нажатий клавиш.TextChanged— изменение текста вTextBox.SelectedIndexChanged— изменение выбора вComboBoxилиListBox.
2. События жизненного цикла объектов:
Load,Shown,FormClosing,FormClosed— для окон Windows Forms.Page_Load,Page_Init— в классическом ASP.NET Web Forms.
3. События компонентов .NET:
Elapsed— у классаSystem.Timers.Timer.Changed,Created,Deleted,Renamed— уFileSystemWatcherдля отслеживания файловой системы.CollectionChanged— уObservableCollection<T>для уведомлений об изменении коллекции (используется в WPF привязке данных).
Почему используется шаблон EventHandler? Он стандартизирован и обеспечивает безопасность типов. Второй параметр e наследуется от EventArgs и может содержать дополнительную информацию о событии.
// Пример объявления и вызова собственного события
public class OrderProcessor
{
// 1. Объявление события с использованием обобщенного делегата EventHandler<T>
public event EventHandler<OrderProcessedEventArgs> OrderProcessed;
public void ProcessOrder(Order order)
{
// Логика обработки...
// 2. Вызов события (проверка на null обязательна!)
OrderProcessed?.Invoke(this, new OrderProcessedEventArgs { OrderId = order.Id, Time = DateTime.Now });
}
}
// 3. Класс для аргументов события
public class OrderProcessedEventArgs : EventArgs
{
public int OrderId { get; set; }
public DateTime Time { get; set; }
}
// 4. Подписка на событие
processor.OrderProcessed += (sender, e) =>
{
Console.WriteLine($"Order {e.OrderId} processed at {e.Time}");
};
Важно: Всегда используйте ?.Invoke() для потокобезопасного вызова события. Для событий без дополнительных данных используйте стандартный делегат EventHandler.
Ответ 18+ 🔞
А, события в C#! Ну это ж классика, блядь. Смотри, по сути это просто реализация паттерна "наблюдатель", но через делегаты, чтобы всё красиво и типобезопасно было. Ну типа кто-то что-то сделал — крикнул всем, кто подписался: "Эй, я тут событие совершил, делайте что хотите!".
1. События в интерфейсах (WinForms/WPF и прочая хрень):
Click,MouseDown,MouseUp,MouseMove— ну это понятно, мышкой тыкаешь, двигаешь.KeyDown,KeyUp,KeyPress— клаву жмёшь, отпускаешь.TextChanged— в текстбоксе букву поменял, сразу событие.SelectedIndexChanged— в выпадающем списке пункт сменил — оп-па, событие.
2. События жизни объектов (родился, пожил, закрылся):
Load,Shown,FormClosing,FormClosed— для окошек в винформах. Загрузилось, показалось, закрывается, закрылось.Page_Load,Page_Init— в старом-добром ASP.NET Web Forms, там своя атмосфера.
3. События от всяких компонентов .NET:
Elapsed— у таймераSystem.Timers.Timer. Прошло время — триггернулось.Changed,Created,Deleted,Renamed— уFileSystemWatcher. Следит за файлами, как маньяк, и шпилит событиями, если что-то изменилось.CollectionChanged— уObservableCollection<T>. Коллекция поменялась (добавили, убрали элемент) — сразу всем подписчикам сигнал. В WPF на этом вся привязка данных и держится, кстати.
А почему везде этот EventHandler? Да чтобы не выдумывать велосипеды, ёпта! Стандартизировали, безопасность типов есть. Второй параметр e — это наследник EventArgs, в нём можно доп. инфу про событие запихнуть.
// Вот смотри, как своё событие наколхозить
public class OrderProcessor
{
// 1. Объявляем событие. Используем обобщённый делегат EventHandler<T>, это модно.
public event EventHandler<OrderProcessedEventArgs> OrderProcessed;
public void ProcessOrder(Order order)
{
// Тут какая-то бизнес-логика, заказ обрабатываем...
// 2. Вызываем событие. Сначала проверяем, есть ли подписчики, чтобы в null не въехать!
OrderProcessed?.Invoke(this, new OrderProcessedEventArgs { OrderId = order.Id, Time = DateTime.Now });
}
}
// 3. Класс для аргументов события. Наследуемся от EventArgs — это правило хорошего тона.
public class OrderProcessedEventArgs : EventArgs
{
public int OrderId { get; set; }
public DateTime Time { get; set; }
}
// 4. Подписываемся на событие. Можно через лямбду, удобно же.
processor.OrderProcessed += (sender, e) =>
{
Console.WriteLine($"Заказ {e.OrderId} обработан в {e.Time}");
};
Запомни на века: Всегда вызывай через ?.Invoke(). Это потокобезопасно и от ошибок спасёт, если подписчиков вдруг не окажется. А для событий, где кроме факта "произошло" ничего не надо, используй обычный EventHandler без всяких <T>. Всё, вопрос закрыт.