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

Что такое Action?

1.0 Junior🔥 231 комментариев
#Основы C# и .NET

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

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

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

Что такое Action в C#

В C# Action — это встроенный делегат, представляющий метод, который не возвращает значение (void) и может принимать от 0 до 16 параметров. Он является частью пространства имен System и широко используется для инкапсуляции методов, особенно в сценариях, связанных с асинхронным программированием, обработкой событий, LINQ и обратными вызовами (callbacks).

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

  • Сигнатура: Все обобщенные версии Action<T1, T2, ...> возвращают void. Необобщенный Action (без параметров) также возвращает void.
  • Параметры: Может принимать от 0 до 16 входных параметров.
  • Тип делегата: Является предопределенным (built-in) делегатом, что устраняет необходимость вручную объявлять новые типы делегатов для распространенных сигнатур.

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

1. Action без параметров

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

using System;

class Program
{
    static void Main()
    {
        // Создание экземпляра делегата Action
        Action greet = () => Console.WriteLine("Hello, World!");
        
        // Вызов
        greet(); // Вывод: Hello, World!

        // Или через именованный метод
        Action greetMethod = SayHello;
        greetMethod();
    }

    static void SayHello()
    {
        Console.WriteLine("Привет!");
    }
}

2. Action с параметрами

Инкапсуляция методов, принимающих один или несколько параметров.

using System;

class Program
{
    static void Main()
    {
        // Action с одним параметром (тип string)
        Action<string> printMessage = (message) => Console.WriteLine(message);
        printMessage("Action с одним параметром.");

        // Action с двумя параметрами
        Action<int, int> sumAndPrint = (x, y) =>
        {
            int result = x + y;
            Console.WriteLine($"Сумма: {result}");
        };
        sumAndPrint(5, 3); // Вывод: Сумма: 8

        // Передача именованного метода
        Action<string, int> repeatPrint = RepeatMessage;
        repeatPrint("ABC", 3); // Вывод: ABC ABC ABC
    }

    static void RepeatMessage(string msg, int count)
    {
        for (int i = 0; i < count; i++)
        {
            Console.Write(msg + " ");
        }
        Console.WriteLine();
    }
}

3. Использование в качестве параметра метода (callback)

Один из самых распространенных сценариев — передача Action в метод для выполнения произвольного кода.

using System;

class DataProcessor
{
    // Метод принимает Action для обработки каждого элемента
    public void ProcessData(int[] data, Action<int> processor)
    {
        foreach (var item in data)
        {
            processor(item); // Вызов переданного действия
        }
    }
}

class Program
{
    static void Main()
    {
        var processor = new DataProcessor();
        int[] numbers = { 1, 2, 3, 4, 5 };

        // Передаем разные обработчики через Action
        Console.WriteLine("Квадраты:");
        processor.ProcessData(numbers, x => Console.WriteLine(x * x));

        Console.WriteLine("Четные?");
        processor.ProcessData(numbers, x => Console.WriteLine(x % 2 == 0));
    }
}

4. Использование с многопоточностью (Task.Run, Parallel)

Action естественно интегрируется с API параллельного и асинхронного программирования.

using System;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        // Запуск действия в отдельном потоке через Task
        Action heavyWork = () =>
        {
            Console.WriteLine("Начало тяжелой работы в потоке: " + Task.CurrentId);
            Task.Delay(1000).Wait();
            Console.WriteLine("Завершение работы.");
        };

        Task.Run(heavyWork).Wait();

        // Использование в Parallel.ForEach
        Action<int> parallelAction = i =>
        {
            Console.WriteLine($"Обработка элемента {i} в потоке {Task.CurrentId}");
        };

        Parallel.ForEach(new[] { 10, 20, 30, 40, 50 }, parallelAction);
    }
}

Ключевые отличия от других делегатов

  • Action vs Func: Func<TResult> всегда возвращает значение (типа TResult), в то время как Action всегда возвращает void. Func используется, когда нужен результат выполнения.
  • Action vs делегаты, объявленные вручную: Использование Action делает код чище и стандартнее, так как не требует объявления отдельного типа делегата для распространенных сигнатур.
  • Action vs события: Action может быть использован для простой реализации шаблона "публикация-подписка", но для полноценных событий рекомендуется использовать event с делегатом EventHandler или EventHandler<T>, так как это обеспечивает лучшую инкапсуляцию и безопасность.

Преимущества использования Action

  1. Упрощение кода: Устраняет необходимость в объявлении лишних пользовательских делегатов.
  2. Универсальность: Позволяет передавать методы как объекты, что особенно полезно в шаблонах, таких как Strategy.
  3. Интеграция с LINQ и асинхронными операциями: Многие методы в .NET (например, List.ForEach, Parallel.Invoke) принимают Action в качестве параметра.
  4. Лямбда-выражения: Отлично сочетается с лямбда-выражениями для написания компактного и читаемого кода "на лету".

Заключение

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

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