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

В чем различия базовых делегатов в .NET?

1.8 Middle🔥 202 комментариев
#Основы C# и .NET

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

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

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

Различия базовых делегатов в .NET

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

Action<T> и его варианты

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

// Базовые варианты Action
Action actionWithoutParams = () => Console.WriteLine("Hello");
Action<int> actionWithOneParam = (x) => Console.WriteLine(x);
Action<int, string> actionWithTwoParams = (x, s) => Console.WriteLine($"{s}: {x}");

// Использование
actionWithoutParams(); // Вывод: Hello
actionWithOneParam(42); // Вывод: 42
actionWithTwoParams(10, "Count"); // Вывод: Count: 10

Ключевые особенности Action:

  • Возвращаемый тип всегда void
  • Поддерживает от 0 до 16 параметров (в .NET Framework) и до 8 в .NET Core/5+
  • Часто используется для обработчиков событий и callback-ов без возврата значения

Func<T> и его варианты

Делегаты семейства Func представляют методы, которые возвращают значение.

// Последний параметр - возвращаемый тип
Func<int> funcWithoutParams = () => 42;
Func<int, string> funcWithOneParam = (x) => x.ToString();
Func<int, string, bool> funcWithTwoParams = (x, s) => s.Length == x;

// Использование
int result1 = funcWithoutParams(); // 42
string result2 = funcWithOneParam(100); // "100"
bool result3 = funcWithTwoParams(3, "abc"); // true

Ключевые особенности Func:

  • Всегда возвращает значение (последний generic-параметр)
  • Поддерживает от 0 до 16 входных параметров + 1 возвращаемый
  • Широко используется в LINQ и функциональном программировании

Predicate<T>

Predicate<T> — это специализированный делегат для проверки условий.

Predicate<int> isEven = (x) => x % 2 == 0;
Predicate<string> isNotEmpty = (s) => !string.IsNullOrEmpty(s);

// Использование
bool test1 = isEven(10); // true
bool test2 = isNotEmpty(""); // false

// Пример с коллекциями
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
List<int> evenNumbers = numbers.FindAll(isEven); // [2, 4]

Ключевые особенности Predicate:

  • Всегда возвращает bool
  • Принимает ровно один параметр
  • Исторически использовался в методах типа FindAll, RemoveAll в коллекциях

Comparison<T>

Comparison<T> используется для сравнения двух объектов.

Comparison<string> lengthComparer = (x, y) => x.Length.CompareTo(y.Length);
Comparison<int> descendingComparer = (x, y) => y.CompareTo(x);

// Использование
List<string> words = new List<string> { "apple", "kiwi", "banana" };
words.Sort(lengthComparer); // Сортировка по длине: kiwi, apple, banana

List<int> numbers = new List<int> { 5, 1, 3, 2, 4 };
numbers.Sort(descendingComparer); // Сортировка по убыванию: 5, 4, 3, 2, 1

Ключевые особенности Comparison:

  • Возвращает int (-1, 0, 1) как стандартный метод сравнения
  • Принимает два параметра одного типа
  • Используется в методах сортировки

Сравнительная таблица

ДелегатВозвращаемый типКоличество параметровОсновное назначение
Actionvoid0-16Операции без возврата значения
FuncЛюбой0-16 входных + 1 возвращаемыйОперации с возвратом значения
Predicate<T>bool1Проверка условий, фильтрация
Comparison<T>int2Сравнение двух объектов

Практические рекомендации

  1. Используйте Action/Func вместо создания кастомных делегатов, если их сигнатура подходит
  2. Predicate<T> можно заменить на Func<T, bool> — в современных версиях .NET это предпочтительнее
  3. Для асинхронных операций используйте Func<Task> и Func<Task<TResult>>
  4. EventHandler и EventHandler<T> — специальные делегаты для событийной модели

Пример замены Predicate на Func

// Старый стиль с Predicate
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var evens = numbers.FindAll(x => x % 2 == 0);

// Новый стиль с Func (через метод расширения)
var evens2 = numbers.Where(x => x % 2 == 0).ToList();

Базовые делегаты в .NET предоставляют унифицированный, типобезопасный способ работы с методами как с объектами, что является фундаментом для многих возможностей платформы, включая LINQ, асинхронное программирование и событийную модель. Выбор конкретного делегата зависит от требуемой сигнатуры метода и семантики операции.

В чем различия базовых делегатов в .NET? | PrepBro