Встречается на 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
интервью вопросы и ответы