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

В чём разница между Event и Action?

2.3 Middle🔥 211 комментариев
#C# и ООП#Паттерны проектирования

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

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

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

Разница между Event и Action в Unity/C#

В контексте Unity и C# Event и Action — это два ключевых механизма для реализации делегатов и событийной архитектуры, но они имеют фундаментальные различия в назначении, безопасности и использовании. Оба позволяют реализовать шаблон Наблюдатель (Observer), но с разной степенью инкапсуляции и контроля.

1. Action — Обобщённый делегат без возвращаемого значения

Action — это предопределённый обобщённый делегат из пространства имён System, который не возвращает значение (void). Он используется для инкапсуляции методов, которые выполняют действие без параметров или с параметрами (до 16 в Action<T1, T2, ...>).

Ключевые характеристики:

  • Публичный доступ: Подписчики могут как добавлять (+=), так и удалять (-=) методы, а также вызывать делегат напрямую (если не используется событийный синтаксис).
  • Простота: Минималистичный синтаксис, идеален для внутренних или безопасных сценариев.
  • Нет встроенной безопасности инкапсуляции: Вне класса, содержащего Action, его можно вызвать напрямую, что может привести к непреднамеренному поведению.
public class ButtonWithAction
{
    public Action OnClicked; // Простой делегат Action

    public void Click()
    {
        Debug.Log("Button clicked.");
        // Любой подписчик может вызвать OnClicked() напрямую извне — это небезопасно!
        OnClicked?.Invoke(); // Проверка на null перед вызовом
    }
}

// Использование
ButtonWithAction button = new ButtonWithAction();
button.OnClicked += () => Debug.Log("UI Updated!");
button.OnClicked += PlaySound;
button.Click(); // Вызовет все подписанные методы
// button.OnClicked.Invoke(); // НЕБЕЗОПАСНО: Прямой вызов возможен!

2. Event — Безопасный механизм на основе делегата

Event — это модификатор для делегата, который добавляет слой инкапсуляции и безопасную модель издателя-подписчика (Publisher-Subscriber). Событие (event) базируется на делегате (часто Action или EventHandler).

Ключевые характеристики:

  • Инкапсуляция: Вне класса-издателя подписчики могут только подписываться (+=) и отписываться (-=). Прямой вызов события возможен только внутри класса, который его объявил.
  • Безопасность: Защищает от случайного или злонамеренного вызова, очистки всех подписок (=) внешним кодом.
  • Стандарт в Unity: Многие встроенные системы Unity (UI, Input) используют события.
public class ButtonWithEvent
{
    // Объявление события на основе делегата Action
    public event Action OnClicked;

    public void Click()
    {
        Debug.Log("Button clicked.");
        // Только этот класс может вызвать событие
        OnClicked?.Invoke();
    }
}

// Использование
ButtonWithEvent button = new ButtonWithEvent();
button.OnClicked += () => Debug.Log("UI Updated!");
button.OnClicked += PlaySound;
button.Click(); // Корректно вызовет все подписанные методы
// button.OnClicked.Invoke(); // ОШИБКА КОМПИЛЯЦИИ: нельзя вызвать извне!
// button.OnClicked = null;   // ОШИБКА КОМПИЛЯЦИИ: нельзя переопределить извне!

Сводная таблица различий

КритерийAction (как поле)Event (на основе делегата)
ИнкапсуляцияОтсутствует. Внешний код может вызывать и перезаписывать.Присутствует. Внешний код только добавляет/удаляет подписчиков.
БезопасностьНизкая. Риск непреднамеренного вызова или очистки.Высокая. Вызов — исключительная прерогатива класса-издателя.
Синтаксисpublic Action OnEvent;public event Action OnEvent;
ИдиоматикаЧаще используется для внутренней коммуникации в классе или в безопасных контекстах.Стандарт для публичных уведомлений, реализация шаблона Наблюдатель.
Возможность вызова извнеДа (если публичный).Нет (только из класса-объявителя).

Практические рекомендации для Unity-разработчика

  1. Всегда используйте event для публичных уведомлений, которые являются частью API вашего класса (например, OnDamageTaken, OnItemCollected). Это профессиональный стандарт и защита от ошибок.
  2. Action можно использовать внутри класса как приватное поле для организации кода или в локальных сценариях, где безопасность не критична (например, callback в пуле объектов).
  3. UnityEvents — это особая, сериализуемая версия событий в Unity для инспектора. Они медленнее, но позволяют настраивать связи через Editor без написания кода.
    using UnityEngine;
    using UnityEngine.Events;
    
    public class GameEventExample : MonoBehaviour
    {
        // UnityEvent можно настраивать в инспекторе
        public UnityEvent OnGameOver;
    
        void EndGame()
        {
            OnGameOver?.Invoke(); // Вызов
        }
    }
    
  4. Производительность: Прямые вызовы делегатов (Action) немного быстрее, чем event, но разница ничтожна для большинства игровых сценариев. Безопасность и дизайн должны быть приоритетом.

Итог: Action — это тип делегата, а event — защищённая надстройка над ним. Ключевое отличие — в инкапсуляции. event создаёт "безопасную" точку для подписки, где только издатель владеет правом на уведомление подписчиков. В production-коде для публичных взаимодействий между системами предпочтительнее всегда использовать event.

В чём разница между Event и Action? | PrepBro