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

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

1.0 Junior🔥 181 комментариев
#C# и ООП

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

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

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

Разница между Delegate, Action и Func в C# для Unity

В C# и Unity разработке делегаты — это типобезопасные указатели на методы, основа языка для событий и обратных вызовов. Action и Func — это предопределённые обобщённые делегаты, введённые для упрощения кода. Разница между ними фундаментальна и касается как синтаксиса, так и применения.

Ключевые отличия

АспектDelegate (Ключевое слово / Пользовательский делегат)Action (Предопределённый делегат)Func (Предопределённый делегат)
НазначениеБазовый механизм для создания типа делегата.Делегат для методов без возвращаемого значения (void).Делегат для методов с возвращаемым значением.
Возврат значенияОпределяется при объявлении.Всегда void.Всегда возвращает значение. Последний параметр — возвращаемый тип.
ОбъявлениеТребует явного объявления (delegate).Уже объявлен в пространстве имён System.Уже объявлен в пространстве имён System.
ИспользованиеДля специфичных сигнатур или лучшей семантики.Для стандартных void-методов. Упрощает код.Для стандартных методов с возвратом. Упрощает код.

1. Delegate: Базовый механизм

Ключевое слово delegate используется для объявления нового типа делегата. Это необходимо, когда сигнатура метода (типы параметров и возвращаемого значения) уникальна и должна быть явно описана для ясности кода или создания событий.

// 1. Объявление пользовательского делегата
public delegate void DamageHandler(float damageAmount, GameObject damageSource);
public delegate int ScoreCalculator(int baseScore, int multiplier);

public class Player : MonoBehaviour
{
    // 2. Создание события на основе пользовательского делегата
    public event DamageHandler OnDamageTaken;

    void TakeDamage()
    {
        OnDamageTaken?.Invoke(10f, gameObject);
    }
}
  • Преимущество: Читаемость и смысловая нагрузка. DamageHandler яснее, чем Action<float, GameObject>.
  • Недостаток: Требует дополнительного объявления.

2. Action: Делегат для методов без возврата (void)

Action — это готовый обобщённый делегат из пространства имён System. Он представляет метод, который не возвращает значение.

using System; // Не забываем для Action и Func

public class EventManager : MonoBehaviour
{
    // Action без параметров
    public Action OnGameStarted;
    // Action с параметрами (до 16)
    public Action<string, int> OnItemCollected;

    void Start()
    {
        // Подписка метода с подходящей сигнатурой
        OnGameStarted += LogGameStart;
        OnItemCollected += HandleItemCollection;
    }

    void LogGameStart()
    {
        Debug.Log("Game Started!");
    }

    void HandleItemCollection(string itemName, int amount)
    {
        Debug.Log($"Collected {amount} of {itemName}");
    }
}

Где использовать в Unity: Для событий, уведомлений, обратных вызовов, где результат выполнения не важен (например, "игра началась", "предмет подобран").

3. Func: Делегат для методов с возвращаемым значением

Func — противоположность Action. Он всегда возвращает значение. Последний параметр в его объявлении определяет тип возвращаемого значения.

using System;

public class Calculator : MonoBehaviour
{
    // Func, возвращающий int и принимающий два int
    public Func<int, int, int> OnCalculateSum;
    // Func, возвращающий bool без параметров
    public Func<bool> OnCheckStatus;

    void Start()
    {
        OnCalculateSum = (a, b) => a + b; // Лямбда-выражение
        int result = OnCalculateSum(5, 3); // result = 8

        OnCheckStatus = () => Time.time > 10f;
        bool isReady = OnCheckStatus(); // true, если с начала игры прошло >10 сек.
    }

    // Более сложный пример с передачей логики
    public int ProcessCalculation(Func<int, int, int> mathOperation)
    {
        return mathOperation(10, 20);
    }
}

Где использовать в Unity: Для систем, требующих результата — вычисления, проверки условий (Func<bool> для условий UI), загрузки данных.

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

  • Используйте Action и Func по умолчанию для стандартных операций. Они делают код чище и избавляют от лишних объявлений.
  • Создавайте пользовательский delegate, когда:
    *   Сигнатура метода часто повторяется и имеет важное смысловое значение.
    *   Вы объявляете **событие (`event`)** публичным членом класса. `public event Action<...> ...` предпочтительнее `public event Func<...> ...` для событий, так как они обычно лишь уведомляют.
  • Func<bool> — мощный инструмент для инверсии зависимостей. Вы можете передать в систему любую логику проверки извне.
  • Не забывайте про отписку (-=) от Action и Func в OnDestroy или OnDisable для MonoBehaviour, чтобы избежать утечек памяти.

Итог: Delegate — это фундамент и инструмент для создания специфичных типов. Action и Func — готовые, типобезопасные "коробки" для большинства повседневных задач, которые делают код на C# более лаконичным и современным. В Unity они активно используются для реализации шаблона Наблюдатель, создания гибких систем событий и обратных вызовов.