Что такое Delegate
Делегат в C# — это типобезопасный объект, который ссылается на один или несколько методов с определенной сигнатурой. Он позволяет передавать методы как параметры, хранить их в переменных и вызывать динамически, что делает код более гибким и модульным.
Как это работает
Делегат объявляется с помощью ключевого слова delegate, после которого указывается сигнатура метода. Например:
delegate int MathOp(int x, int y);Этот делегат может ссылаться на любой метод, который принимает два целых числа и возвращает целое число. При присваивании метода делегату создается экземпляр делегата, который хранит ссылку на метод. Вызов делегата происходит так же, как вызов обычного метода.
Делегаты являются ссылочными типами и поддерживают групповое преобразование методов: можно присвоить делегату метод с совместимой сигнатурой без явного создания экземпляра.
Multicast-делегаты
Одно из ключевых свойств делегатов — поддержка multicast, то есть возможность хранить ссылки на несколько методов. Это реализуется с помощью операторов += и -= для добавления и удаления методов из списка вызова. При вызове multicast-делегата методы вызываются в порядке их добавления. Если делегат возвращает значение, то возвращается результат последнего вызванного метода, а результаты предыдущих игнорируются.
Пример:
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 и асинхронных операций.
