Ответ
Делегат (delegate) в C# — это типобезопасный указатель на метод. Он определяет сигнатуру метода (возвращаемый тип и параметры), что позволяет передавать методы как аргументы, хранить их в переменных и вызывать позже. Делегаты — основа событийной модели и асинхронных операций в .NET.
Базовое объявление и использование:
// 1. Объявление типа делегата.
delegate int BinaryOperation(int a, int b);
class Program
{
// 2. Методы, совместимые с сигнатурой делегата.
static int Add(int x, int y) => x + y;
static int Multiply(int x, int y) => x * y;
static void Main()
{
// 3. Создание экземпляра делегата.
BinaryOperation operation = Add;
// 4. Вызов метода через делегат.
int result = operation(5, 3); // result = 8
Console.WriteLine(result);
// 5. Multicast делегат: делегат может ссылаться на несколько методов.
operation += Multiply;
// При вызове будут выполнены все методы в порядке добавления.
// Но возвращено будет значение только от последнего.
result = operation(5, 3); // Выполнятся Add(5,3) и Multiply(5,3), result = 15
Console.WriteLine(result);
}
}
Встроенные обобщённые делегаты:
На практике чаще используют готовые типы:
Action<T>— для методов, которые что-то делают, но не возвращают значение (void).Func<T, TResult>— для методов, возвращающих значение.
// Использование Func вместо объявления своего делегата.
Func<int, int, int> operationFunc = Add;
int sum = operationFunc(10, 20); // 30
// Использование Action.
Action<string> logger = (message) => Console.WriteLine($"Log: {message}");
logger("Hello, Delegate!");
Ключевое применение: Обратные вызовы (callbacks), обработка событий, реализация паттернов (например, Стратегия), LINQ.
Ответ 18+ 🔞
А, делегаты в C#! Ну это ж классика, блядь, основа основ, как водка в России. Сидишь такой, пишешь код, и тут — бац! — надо метод как переменную передать. А как, спрашивается? Вот тут они и появляются, эти самые делегаты.
Представь себе, делегат — это такой типобезопасный указатель на метод. Не просто адрес в памяти, как у каких-нибудь диких сишников, а культурный, воспитанный указатель, который знает, какие у метода параметры и что он возвращает. Безопасность, мать его, типобезопасность!
Объявляется это чудо просто:
delegate int BinaryOperation(int a, int b);
Вот смотри, что мы сделали. Мы сказали: «Слушай, компилятор, будет у нас такой тип — BinaryOperation. Всё, что под него подходит, должно быть методом, который принимает два int и возвращает один int. Запомнил?» И компилятор запоминает, сука.
Дальше пишешь обычные методы:
static int Add(int x, int y) => x + y;
static int Multiply(int x, int y) => x * y;
И вот тут начинается магия, ёпта. Берёшь и присваиваешь метод переменной делегата:
BinaryOperation operation = Add;
Всё! Теперь operation — это не просто переменная, это прикинь, целый метод Add в ней сидит! Вызываешь как обычную функцию:
int result = operation(5, 3); // result = 8
И работает, блядь! А самое охуенное — multicast. Это когда в одну переменную делегата можно навешать кучу методов, и они все по очереди вызовутся. Как поезд с вагонами.
operation += Multiply; // Добавили второй метод
result = operation(5, 3); // Сначала Add(5,3), потом Multiply(5,3)
Тут есть один подвох, конечно. Возвращаемое значение будет только от последнего метода в цепочке. От Multiply в нашем случае. Так что если тебе нужны результаты всех — собирай их в списки внутри методов, а не надейся на делегата.
Но реально, в жизни своё объявление делегатов пишешь редко. Умные дядьки из Microsoft уже всё придумали за нас. Есть Action — для методов, которые ничего не возвращают (то есть void). И есть Func — для методов, которые что-то возвращают.
Смотри, как красиво:
// Раньше: delegate int BinaryOperation(int a, int b);
// Сейчас:
Func<int, int, int> operationFunc = Add;
int sum = operationFunc(10, 20); // 30
// Для пустых методов — Action.
Action<string> logger = (message) => Console.WriteLine($"Log: {message}");
logger("Привет, делегат!"); // Выведет "Log: Привет, делегат!"
Красота, да и только! Никакого лишнего кода. Func<in T1, in T2, ..., out TResult>. Последний тип — это что метод возвращает, а всё перед ним — что принимает.
Где это всё применяется? Да везде, сука! Обратные вызовы (callbacks), события (вся эта ваша событийная модель на них стоит), паттерны вроде «Стратегии». Ну и LINQ, конечно, куда ж без него. Там внутри вся эта мощь и крутится. Так что учи, это не просто синтаксический сахар, а реально мощный инструмент.