Встречается на 77% собеседований по C#
Что такое делегат
Делегат в C# — это тип, который безопасно инкапсулирует метод, подобно указателю на функцию в других языках, но с проверкой типов во время компиляции. Делегаты позволяют передавать методы как параметры, реализовывать обратные вызовы, события и асинхронные операции, делая код гибким и масштабируемым.
Как это работает
Делегат объявляется с сигнатурой, определяющей параметры и возвращаемое значение. Экземпляр делегата может ссылаться на любой метод с совместимой сигнатурой. Вызов делегата аналогичен вызову метода, на который он ссылается. Делегаты являются ссылочными типами и поддерживают многоадресность: один делегат может ссылаться на несколько методов, которые вызываются последовательно.
Пример
csharp
// Определение делегата
public delegate int Operation(int x, int y);
class Program
{
static void Main()
{
// Создание экземпляра делегата, ссылающегося на метод Add
Operation op = Add;
text
// Вызов метода через делегат
int result = op(5, 5);
Console.WriteLine(result); // Вывод: 10
// Делегат теперь ссылается на метод Subtract
op = Subtract;
// Повторный вызов метода через делегат
result = op(10, 5);
Console.WriteLine(result); // Вывод: 5
}
static int Add(int x, int y) => x + y;
static int Subtract(int x, int y) => x - y;}
text
В этом примере делегат `Operation` может ссылаться на любой метод, принимающий два целых числа и возвращающий целое. Сначала он указывает на `Add`, затем на `Subtract`, демонстрируя динамическую смену вызываемого метода.
## Подводные камни
- **Сигнатура должна совпадать точно**: делегат неявно не преобразуется к другому делегату с похожей сигнатурой, даже если параметры совместимы.
- **Многоадресные делегаты**: если делегат ссылается на несколько методов, возвращаемое значение берется от последнего вызванного метода. Для проверки результата каждого метода нужно использовать `GetInvocationList()`.
- **NullReferenceException**: вызов делегата без ссылки на метод приведет к исключению. Проверяйте делегат на `null` или используйте оператор `?.`.
- **Захват переменных**: в лямбда-выражениях и анонимных методах делегаты захватывают переменные из внешнего контекста, что может привести к неожиданному поведению при изменении переменных после создания делегата.
## Когда использовать
Делегаты применяются для:
- Реализации обратных вызовов (например, в асинхронных операциях).
- Событий: события в C# основаны на делегатах.
- Реализации шаблонов проектирования, таких как Observer и Strategy.
- Передачи методов в качестве параметров для настройки поведения (например, LINQ-методы принимают делегаты).
В современном C# вместо явного объявления делегатов часто используют встроенные типы `Action` и `Func`, которые покрывают большинство сигнатур. Однако понимание делегатов необходимо для работы с событиями и старым кодом.
## Коротко
- Делегат — типобезопасный указатель на метод.
- Позволяет передавать методы как параметры и реализовывать события.
- Многоадресные делегаты вызывают несколько методов, но возвращают результат последнего.
- Вместо явных делегатов часто используют `Action` и `Func`.Похожие вопросы
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы
