Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Виды делегатов в 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;
Сравнительная таблица основных типов
| Тип делегата | Возвращаемое значение | Основное назначение |
|---|---|---|
| Action | void | Выполнение действий |
| Func | Любой тип | Вычисления и преобразования |
| Predicate | bool | Проверка условий |
| EventHandler | void | Обработка событий |
| Пользовательский | Любой тип | Специфичные сценарии |
Ключевые особенности использования
- Типобезопасность: компилятор проверяет соответствие сигнатур методов
- Иммутабельность: делегаты являются неизменяемыми, операции
+=и-=создают новый экземпляр - Интеграция с LINQ: лямбда-выражения и делегаты — основа Language Integrated Query
- Асинхронность: современные делегаты легко комбинируются с
async/await
Выбор конкретного вида делегата зависит от контекста: для событий используют EventHandler, для вычислений — Func, для действий без результата — Action, а для сложных сценариев создают пользовательские делегаты. В современном C# предпочтение отдается встроенным обобщенным делегатам, так как они уменьшают количество объявляемых типов и стандартизируют код.