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

Что такое Func?

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

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

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

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

Что такое Func в C# и Unity?

Func — это встроенный в C# обобщённый делегат (generic delegate), который представляет метод, возвращающий значение. Он является частью библиотеки .NET и активно используется в Unity для работы с событиями, асинхронными операциями, LINQ-запросами и функциональным программированием.

Основные характеристики Func

  • Это делегат: Func позволяет хранить ссылки на методы, как и любой другой делегат, но с чётко определённой сигнатурой, заданной через обобщённые параметры (Generics).
  • Всегда возвращает значение: В отличие от делегата Action, который представляет метод, не возвращающий значение (void), Func всегда должен возвращать результат.
  • Гибкость через generics: Последний обобщённый параметр в определении Func указывает на тип возвращаемого значения. Все предыдущие параметры — это типы входных аргументов метода.

Синтаксис и варианты

В пространстве имен System определено 17 перегрузок Func (от Func<TResult> до Func<T1, T2, ..., T16, TResult>), которые могут принимать от 0 до 16 входных параметров.

// Без параметров, возвращает int
Func<int> getRandomNumber;

// С одним параметром (string), возвращает int
Func<string, int> getStringLength;

// С двумя параметрами (int, int), возвращает int
Func<int, int, int> sum;

// С тремя параметрами (float, float, float), возвращает float
Func<float, float, float, float> calculateAverage;

Практическое применение в Unity

1. Передача методов как параметров (колбэки)

Часто используется для создания гибких систем, где логика может быть определена снаружи.

public class DamageCalculator
{
    // Метод принимает формулу расчета урона в виде Func<int, int, int>
    public int CalculateDamage(int baseDamage, int multiplier, Func<int, int, int> damageFormula)
    {
        return damageFormula(baseDamage, multiplier);
    }
}

// Где-то в другом классе, например, в Enemy или Player:
void Start()
{
    DamageCalculator calculator = new DamageCalculator();

    // Передаем лямбда-выражение как формулу
    int totalDamage = calculator.CalculateDamage(10, 2, (baseDmg, mult) => baseDmg * mult);
    Debug.Log($"Урон: {totalDamage}"); // Выведет: Урон: 20

    // Или передаем именованный метод
    totalDamage = calculator.CalculateDamage(10, 2, ComplexDamageFormula);
}

int ComplexDamageFormula(int baseDmg, int mult)
{
    return (baseDmg * mult) + Random.Range(0, 5);
}

2. Кеширование результатов вычислений (мемоизация)

Полезно для оптимизации дорогостоящих операций, которые вызываются многократно с одинаковыми параметрами.

public class Memoizer
{
    private Dictionary<string, int> _cache = new Dictionary<string, int>();

    public int MemoizedCalculation(Func<int> expensiveCalculation, string key)
    {
        if (!_cache.ContainsKey(key))
        {
            _cache[key] = expensiveCalculation();
        }
        return _cache[key];
    }
}

3. Работа с LINQ

Большинство методов LINQ (Where, Select, First) принимают Func в качестве параметра-предиката или селектора.

List<GameObject> enemies = new List<GameObject>(GameObject.FindGameObjectsWithTag("Enemy"));

// Func<GameObject, bool> для фильтрации
var aliveEnemies = enemies.Where(e => e.GetComponent<Health>().CurrentHealth > 0);

// Func<GameObject, float> для преобразования
var enemiesHealth = enemies.Select(e => e.GetComponent<Health>().CurrentHealth);

4. Асинхронные операции и задачи

Func можно использовать для обёртывания кода, который будет выполнен асинхронно.

public async Task<int> LoadDataAsync(Func<Task<int>> dataLoader)
{
    Debug.Log("Начало загрузки...");
    int result = await dataLoader();
    Debug.Log($"Загружено: {result}");
    return result;
}

// Использование:
await LoadDataAsync(async () => 
{
    await Task.Delay(1000); // Имитация долгой операции
    return 42;
});

Ключевые преимущества использования Func

  • Уменьшение связанности кода: Классы не зависят от конкретных реализаций, а только от абстрактной сигнатуры метода.
  • Повышение гибкости и переиспользуемости: Позволяет легко подменять алгоритмы "на лету".
  • Удобство работы с LINQ и коллекциями: Является основой для функциональных операций над данными.
  • Лёгкость использования с лямбда-выражениями: Делает код более компактным и читаемым.

Отличие от Action и Predicate

  • Action — делегат для методов без возвращаемого значения (void).
  • Predicate<T> — специализированный делегат, возвращающий только bool (по сути, это аналог Func<T, bool>). Часто используется в старых коллекциях (List.Find).

Заключение

В Unity Func становится особенно полезным при создании систем искусственного интеллекта (где различные поведения можно инжектировать как функции), диалоговых систем (с условиями и действиями, выраженными через делегаты), кастомизируемых способностей персонажей или в любых UI-системах, где обработчики событий могут динамически подменяться. Это мощный инструмент, который способствует написанию чистого, модульного и поддерживаемого кода в парадигме функционального программирования, постепенно внедряемой в объектно-ориентированную среду Unity.

Что такое Func? | PrepBro