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

Какие знаешь виды делегатов?

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

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

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

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

Виды делегатов в C#

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

1. Стандартные (пользовательские) делегаты

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

// Объявление пользовательского делегата
public delegate int OperationDelegate(int a, int b);

// Использование
public class Calculator
{
    public int Add(int x, int y) => x + y;
    public int Multiply(int x, int y) => x * y;
}

var calc = new Calculator();
OperationDelegate operation = calc.Add;
var result = operation(5, 3); // 8

2. Встроенные обобщенные делегаты .NET

В пространстве имен System определены готовые обобщенные делегаты, которые покрывают большинство сценариев.

Action

Представляет метод, который не возвращает значение (void). Существуют версии от 0 до 16 параметров.

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

// Action с параметрами
Action<string, int> showInfo = (name, age) => 
    Console.WriteLine($"Name: {name}, Age: {age}");

Func

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

// Func с возвращаемым значением
Func<int, int, int> add = (a, b) => a + b;
Func<string, bool> isNotEmpty = s => !string.IsNullOrEmpty(s);

Predicate

Специализированный делегат для проверки условия (возвращает bool). Часто используется в коллекциях.

Predicate<int> isPositive = x => x > 0;
List<int> numbers = new List<int> { -2, 0, 3, 5 };
var positiveNumbers = numbers.FindAll(isPositive);

3. Делегаты для событий (Event-делегаты)

Особый вид делегатов, используемый в шаблоне событий. Следуют соглашению: возвращают void и принимают два параметра — отправитель и аргументы события.

public delegate void EventHandler(object sender, EventArgs e);
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);

// Пример использования
public class Button
{
    public event EventHandler Clicked;
    
    public void Click()
    {
        Clicked?.Invoke(this, EventArgs.Empty);
    }
}

4. Асинхронные делегаты

Поддерживают асинхронный вызов методов через BeginInvoke/EndInvoke (устаревший подход). В современных версиях C# вместо них используют async/await с Task.

public delegate string AsyncDelegate(int delay);

// Устаревший асинхронный вызов (не рекомендуется для нового кода)
AsyncDelegate asyncMethod = SomeLongOperation;
asyncMethod.BeginInvoke(1000, null, null);

5. Ковариантные и контравариантные делегаты

Поддерживают гибкость при работе с наследованием через модификаторы in (контравариантность) и out (ковариантность).

// Контравариантность параметра (in)
delegate void ContravariantDelegate<in T>(T item);

// Ковариантность возвращаемого значения (out)
delegate T CovariantDelegate<out T>();

6. Многоадресные делегаты (Multicast delegates)

Делегаты, которые могут ссылаться на несколько методов одновременно. При вызове выполняются все методы в порядке добавления.

Action multiDelegate = () => Console.Write("First, ");
multiDelegate += () => Console.Write("Second, ");
multiDelegate += () => Console.WriteLine("Third");

multiDelegate(); // Вывод: First, Second, Third

7. Анонимные методы и лямбда-выражения

Хотя технически это не отдельный вид делегатов, они представляют собой синтаксический сахар для создания экземпляров делегатов.

// Анонимный метод (устаревший, но поддерживается)
Func<int, int> square = delegate(int x) { return x * x; };

// Лямбда-выражение (современный подход)
Func<int, int, int> sum = (a, b) => a + b;

Сравнительная таблица основных типов

Тип делегатаВозвращаемое значениеОсновное назначение
ActionvoidВыполнение действий
FuncЛюбой типВычисления и преобразования
PredicateboolПроверка условий
EventHandlervoidОбработка событий
ПользовательскийЛюбой типСпецифичные сценарии

Ключевые особенности использования

  • Типобезопасность: компилятор проверяет соответствие сигнатур методов
  • Иммутабельность: делегаты являются неизменяемыми, операции += и -= создают новый экземпляр
  • Интеграция с LINQ: лямбда-выражения и делегаты — основа Language Integrated Query
  • Асинхронность: современные делегаты легко комбинируются с async/await

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