События C# в программировании чем-то похожи на события в повседневной жизни. Рождение, первый шаг, первый день в школе и тому подобное. Разумеется, для программы значимые события выглядят немного иначе. К примеру, загрузилась форма, изменилось значение поля или был создан объект. Понимать события крайне полезно. Но в первую очередь необходимо изучить делегаты C#.

Смотрите моё видео на тему События и делегаты C#

Делегаты C#

Итак, механика событий достаточно проста. Предположим, для класса Character, рассмотренного ранее, мы хотим создать событие. У персонажа могут меняться любые параметры. Для начала обработаем изменение имени персонажа. Персонаж в данном случае является издателем события. Другие классы могут подписаться на получение этого event. Чтобы издатель смог вызвать метод подписчика, зарегистрированный на события, методы должны иметь определенный формат.

И вот мы вплотную подошли к делегатам. По сути своей, это тип, определяющий полную сигнатуру метода события. К примеру, так описывается делегат, не имеющий параметров.

/// <summary>
/// Делегат.
/// </summary> 
/// <param name="sender"> Объект - отправитель события.</param>
/// <param name="e"> Передаваемые аргументы.</param>
public delegate void EventHandler (Object sender, EventArgs e)

На самом деле, подобное описание делегатов не обязательно. Однако рекомендуется использовать общепринятое соглашение: первый параметр — издатель, второй — объект с параметрами. Класс EventArgs не содержит данных по событию. При необходимости передать что-либо подписчику, необходимо унаследовать этот класс и наделить потомка необходимыми свойствами.

Подпишись на группу Вконтакте и Телеграм-канал. Там еще больше полезного контента для программистов.
А на YouTube-канале ты найдешь обучающие видео по программированию. Подписывайся!

События C# и их вызовы

Делегат, в первую очередь, описывает метод подписчика. Также делегат сообщает издателю, какой метод будет вызван. Делегаты одного класса могут использоваться в разных событиях и издателях. Итак, добавим событие с именем NameChanged класса EventHandler.

public event EventHandler NameChanged;

Обязательно нужно указывать модификатор public, чтобы к событию был доступ извне. Для генерации event нужно просто вызвать его, как обычный метод.

NameChanged(this, new EventArgs());

Далее, рассмотрим, как может выглядеть свойство Name.

/// <summary>
/// Закрытое поле "Имя".
/// </summary>
private string _name; 

/// <summary>
/// Свойство "Имя".
/// </summary>
public string Name
{
    get
    {
        return _name;
    }

    set
    {
        if (value == "" ||
            value == string.Empty)
        {
            throw new ArgumentException("Укажите имя.");
        }

        _name = value;

        if (NameChanged != null)
        {
            NameChanged(this, new EventArgs());
        }
    }
}

И, соответственно, рассмотрим пример использования в консольном приложении.

static void Main(string[] args)
{
    var character = new Character();
    character.NameChanged += new EventHandler(NameChanged);

    character.Name = "Гудини";
            
    Console.ReadLine();
}        

/// <summary>
/// Событие изменения имени.
/// </summary>
/// <param name="sender"> Издатель.</param>
/// <param name="e"></param>
public static void NameChanged(Object sender, EventArgs e)
{
    Character character = (Character)sender;
    Console.WriteLine($"Новое имя персонажа {character.Name}.");
}

Для того, чтобы добавить обработчик события, используется +=. Если же нужно обработчик удалить, используется -=. Первое время делегаты выглядят сложно и запутанно, однако спустя пару опытов, жизнь становится значительно проще.

Анонимные методы

Рассмотренный ранее вариант обработки событий прекрасен. Однако когда для реализации делегата достаточно пары строк, писать подобный код нерационально. Да и скучно, если таких событий множество. Для подобных ситуаций есть анонимные метод, позволяющие обрабатывать event. Рассмотрим обработку изменения имени при помощи анонимного метода.

static void Main(string[] args)
{
    var character = new Character();
    character.NameChanged += delegate (Object sender, EventArgs e)
    {
        Character person = (Character)sender;
        Console.WriteLine($"Новое имя персонажа {person.Name}.");
    };

    character.Name = "Гудини";
            
    Console.ReadLine();
}

После ключевого слова delegate в скобках указаны параметры, передаваемые обработчику события. Реализация обработки события описывается в круглых скобках. Анонимным метод зовется потому, как не имеет явно указанного имени.

Полагаю, это достаточный минимум для начала работы с событиями и делегатами. Удачных вам экспериментов, коллеги.

Кроме того, рекомендую прочитать статью Переменные C#. А также подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.