← Назад к вопросам

Что такое делегаты и события в C#? В чем разница между ними?

2.3 Middle🔥 171 комментариев
#C# и ООП

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Делегаты и события в C#: фундамент паттерна "Наблюдатель"

Что такое делегаты?

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

// Объявление делегата
public delegate void LogMessageDelegate(string message);

// Метод, соответствующий сигнатуре делегата
public void WriteToConsole(string message)
{
    Console.WriteLine($"Console: {message}");
}

// Использование делегата
LogMessageDelegate logger = WriteToConsole;
logger("Привет, мир!"); // Вызов метода через делегат

Ключевые особенности делегатов:

  • Типобезопасность — компилятор проверяет соответствие сигнатур
  • Поддержка multicast — делегат может ссылаться на несколько методов (+=, -=)
  • Анонимные методы и лямбда-выражения — можно создавать инлайн-методы
  • Использование в LINQ — многие операции LINQ основаны на делегатах

Что такое события?

События — это специальный вид делегата, реализующий паттерн "Издатель-Подписчик" (Publisher-Subscriber). События обеспечивают механизм уведомления объектов о происходящих действиях, при этом минимизируя связность между компонентами.

public class TemperatureSensor
{
    // Объявление события
    public event Action<TemperatureSensor, double> TemperatureChanged;
    
    private double _temperature;
    
    public double Temperature
    {
        get => _temperature;
        set
        {
            if (_temperature != value)
            {
                _temperature = value;
                // Вызов события
                OnTemperatureChanged(value);
            }
        }
    }
    
    protected virtual void OnTemperatureChanged(double newTemperature)
    {
        TemperatureChanged?.Invoke(this, newTemperature);
    }
}

// Подписка на событие
var sensor = new TemperatureSensor();
sensor.TemperatureChanged += (sender, temp) => 
{
    Console.WriteLine($"Температура изменилась: {temp}°C");
};

Основные различия между делегатами и событиями

КритерийДелегатыСобытия
НазначениеОбщий механизм ссылок на методыСпециализированный механизм для уведомлений
ИнкапсуляцияПубличное поле (можно вызвать извне)Доступно только для добавления/удаления подписчиков
Модификаторы доступаЛюбые модификаторыОбычно public, но с ограниченными операциями
ИнициализацияМожет быть nullАвтоматически инициализируется как null
ПотокобезопасностьНет встроенной поддержки?.Invoke() обеспечивает безопасность
ИспользованиеОбщее назначениеРеализация паттерна "Наблюдатель"

Практические отличия

  1. Инвариант вызова:

    // Делегат - может быть вызван из любого места
    public delegate void MyDelegate();
    public MyDelegate myDelegate;
    
    // Вызов возможен извне класса
    myDelegate?.Invoke();
    
    // Событие - можно вызвать только внутри класса-издателя
    public event Action MyEvent;
    
    // Вне класса можно только подписаться/отписаться
    // MyEvent?.Invoke(); // Ошибка компиляции - доступно только в классе-владельце
    
  2. Модификаторы доступа к операциям:

    • Для событий доступны только += и -= снаружи класса
    • Для делегатов возможны присваивание (=), вызов и проверка на null
  3. Архитектурное назначение:

    • Делегаты — механизм обратных вызовов (callbacks)
    • События — реализация слабой связанности между компонентами

Когда что использовать?

Используйте делегаты, когда:

  • Нужно передать метод как параметр (коллбэки)
  • Реализуете стратегии или команды
  • Работаете с LINQ и функциональным программированием
  • Создаёте обобщённые алгоритмы

Используйте события, когда:

  • Реализуете паттерн "Наблюдатель"
  • Создаёте пользовательские элементы управления UI
  • Разрабатываете игровые системы (Unity-события)
  • Строите слабосвязанную архитектуру

В контексте Unity

В Unity события широко используются через механизм UnityEvent, который является сериализуемой версией событий C#:

public class GameManager : MonoBehaviour
{
    public UnityEvent OnGameStart;
    
    void Start()
    {
        // Вызов события, на которое можно подписаться через Inspector
        OnGameStart?.Invoke();
    }
}

Делегаты в Unity часто используются для:

  • Коллбэков анимаций и асинхронных операций
  • Системы команд и действий
  • Динамического поведения AI

Заключение

Делегаты и события — взаимодополняющие концепции, где делегаты предоставляют фундаментальный механизм ссылок на методы, а события добавляют уровень инкапсуляции и безопасности для реализации паттерна издатель-подписчик. Понимание их различий критически важно для создания гибких, поддерживаемых и слабосвязанных архитектур, что особенно ценится в game development на Unity, где компонентный подход и событийно-ориентированное программирование являются основополагающими принципами.