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

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

1.2 Junior🔥 212 комментариев
#ООП и паттерны проектирования#Основы C# и .NET

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

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

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

# Разница между Action и Func в C#

Общая концепция делегатов

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

Action — делегат без возвращаемого значения

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

// Action без параметров
Action actionWithoutParams = () => Console.WriteLine("Hello, World!");
actionWithoutParams();

// Action с одним параметром
Action<string> actionWithOneParam = (message) => Console.WriteLine(message);
actionWithOneParam("Привет!");

// Action с несколькими параметрами
Action<int, string, bool> actionWithMultipleParams = (id, name, isActive) =>
{
    Console.WriteLine($"ID: {id}, Name: {name}, Active: {isActive}");
};
actionWithMultipleParams(1, "Test", true);

Action имеет несколько перегрузок для различного количества параметров (до 16 параметров в .NET Framework). Все версии Action возвращают void.

Func — делегат с возвращаемым значением

Func — это делегат, который всегда возвращает значение последнего указанного типа параметра. Последний тип в объявлении Func всегда является типом возвращаемого значения.

// Func без параметров, возвращающий строку
Func<string> funcWithoutParams = () => "Hello, World!";
string result1 = funcWithoutParams();

// Func с одним параметром, возвращающий int
Func<string, int> funcWithOneParam = (text) => text.Length;
int length = funcWithOneParam("Привет");

// Func с несколькими параметрами
Func<int, int, string> funcWithMultipleParams = (a, b) => 
{
    int sum = a + b;
    return $"Сумма: {sum}";
};
string result2 = funcWithMultipleParams(5, 3);

Func также имеет перегрузки для различного количества параметров (до 16 входных параметров). Последний тип-параметр всегда определяет тип возвращаемого значения.

Ключевые различия

1. Возвращаемое значение

  • Action: Всегда возвращает void (не возвращает значение)
  • Func: Всегда возвращает значение указанного типа

2. Сигнатура объявления

// Action - без указания возвращаемого типа
Action<T1, T2, ..., T16>

// Func - последний параметр указывает тип возвращаемого значения
Func<T1, T2, ..., TResult>

3. Типичные сценарии использования

  • Action: Выполнение операций без необходимости возврата результата (логирование, уведомления, побочные эффекты)
  • Func: Вычисления, преобразования данных, получение результатов операций

Практические примеры использования

Пример с Action — обработка коллекций

List<string> names = new List<string> { "Анна", "Борис", "Виктор" };

// Использование Action для обработки каждого элемента
names.ForEach((name) => Console.WriteLine($"Имя: {name}"));

// Или с явным объявлением Action
Action<string> printAction = (name) => Console.WriteLine($"Имя: {name}");
names.ForEach(printAction);

Пример с Func — преобразование данных

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };

// Использование Func для преобразования
List<int> squaredNumbers = numbers.Select((x) => x * x).ToList();

// Или с явным объявлением Func
Func<int, int> squareFunc = (x) => x * x;
List<int> result = numbers.Select(squareFunc).ToList();

Использование в асинхронном программировании

Асинхронные версии

// Async версии для использования с await
Func<Task> asyncFunc = async () =>
{
    await Task.Delay(1000);
    Console.WriteLine("Async operation completed");
};

// Action для асинхронных операций без результата
Action asyncAction = async () =>
{
    await Task.Delay(1000);
    Console.WriteLine("Async action completed");
};

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

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

  • Вам нужно выполнить операцию без возврата результата
  • Вы работаете с обработчиками событий
  • Выполняете побочные эффекты (логирование, изменение состояния)
  • Используете методы типа ForEach для коллекций

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

  • Необходимо преобразовать или вычислить значение
  • Работаете с LINQ операциями (Select, Where, etc.)
  • Реализуете стратегии или фабричные методы
  • Возвращаете результат из анонимного метода

Производительность и внутреннее устройство

Оба делегата являются частью базовой библиотеки классов .NET и имеют оптимизированную реализацию. Однако важно понимать, что при частом использовании могут возникать аллокации памяти, особенно при захвате переменных из внешнего контекста (closures).

// Пример с захватом переменных
int multiplier = 2;

// Action с захватом переменной
Action<int> multiplierAction = (x) => Console.WriteLine(x * multiplier);

// Func с захватом переменной
Func<int, int> multiplierFunc = (x) => x * multiplier;

Заключение

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

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