Встречается на 45% собеседований по C#

Что такое Delegate

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

Как это работает

Делегат объявляется с помощью ключевого слова delegate, после которого указывается сигнатура метода. Например:

csharp
delegate int MathOp(int x, int y);

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

Делегаты являются ссылочными типами и поддерживают групповое преобразование методов: можно присвоить делегату метод с совместимой сигнатурой без явного создания экземпляра.

Multicast-делегаты

Одно из ключевых свойств делегатов — поддержка multicast, то есть возможность хранить ссылки на несколько методов. Это реализуется с помощью операторов += и -= для добавления и удаления методов из списка вызова. При вызове multicast-делегата методы вызываются в порядке их добавления. Если делегат возвращает значение, то возвращается результат последнего вызванного метода, а результаты предыдущих игнорируются.

Пример:

csharp
static int Add(int a, int b) => a + b;
static int Sub(int a, int b) => a - b;

MathOp op = Add;
op += Sub;

int result = op(5, 3); // Вызовет Add, затем Sub, вернет 2 (результат Sub)

Встроенные делегаты

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

  • Action — для методов, возвращающих void, с параметрами до 16.
  • Func — для методов, возвращающих значение, с параметрами до 16 (последний тип в обобщении — тип возвращаемого значения).
  • Predicate<T> — для методов, возвращающих bool и принимающих один параметр типа T.

Использование встроенных делегатов избавляет от необходимости объявлять собственные типы делегатов.

Применение

Делегаты широко используются в C#:

  • Обратные вызовы (callbacks) — передача метода в другой метод для последующего вызова.
  • События (events) — события основаны на делегатах, позволяя подписываться на уведомления.
  • LINQ — методы расширения, такие как Where, Select, принимают делегаты (Func<...>) для определения логики.
  • Асинхронное программирование — делегаты используются в BeginInvoke/EndInvoke (устаревший подход) и в современных паттернах через async/await.

Подводные камни

  • При multicast-вызове, если один из методов выбрасывает исключение, последующие методы не вызываются.
  • Для делегатов с возвращаемым значением в multicast-цепочке возвращается только последний результат, что может быть неочевидно.
  • Делегаты являются неизменяемыми: операции += и -= создают новый делегат, а не изменяют существующий.

Коротко

  • Делегат — типобезопасная ссылка на метод (или несколько методов).
  • Поддерживает multicast через += и -=.
  • Встроенные делегаты Action, Func, Predicate покрывают большинство случаев.
  • Применяется для обратных вызовов, событий, LINQ и асинхронных операций.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы