← Все вопросы

Что такое делегат в C# и зачем он нужен? Не понимаю синтаксис delegate

Задан 13 месяцев назад411 просмотров2 ответа
9

Читаю учебник по C#, дошёл до главы про делегаты (delegate) и совсем запутался. Везде пишут, что «делегат — это указатель на метод», но мне это ничего не объясняет. Зачем вообще передавать метод, если я могу просто вызвать его напрямую?

Вот пример, который меня смущает. Я объявил delegate, но не понимаю, что происходит при присваивании:

delegate int Operation(int a, int b);

class Program
{
    static int Add(int x, int y) => x + y;

    static void Main()
    {
        Operation op = Add;   // вот эта строка непонятна
        Console.WriteLine(op(3, 4));
    }
}

Как op вдруг становится методом Add? И главное — зачем так делать, если можно написать просто Add(3, 4)?

2 ответа

15
✓ Принятый ответ — помог автору

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

В твоём примере Operation — это тип «метод, принимающий два int и возвращающий int». Строка Operation op = Add; кладёт в переменную ссылку на метод Add. Теперь op(3, 4) фактически вызывает Add(3, 4).

Смысл не в том, чтобы заменить прямой вызов, а в том, чтобы передавать поведение как данные. Например, метод сортировки может принимать делегат-компаратор и не знать заранее, как именно сравнивать:

delegate int Operation(int a, int b);

static int Add(int a, int b) => a + b;
static int Mul(int a, int b) => a * b;

static void PrintResult(Operation f, int a, int b)
{
    Console.WriteLine(f(a, b));
}

// один и тот же метод, разное поведение
PrintResult(Add, 3, 4); // 7
PrintResult(Mul, 3, 4); // 12

Именно на делегатах построены события, колбэки и весь LINQ. Так что это не «лишняя обёртка», а основа для гибкого кода.

6

Добавлю аналогию, которая мне в своё время помогла. Делегат — это как «контакт» в телефоне: ты не звонишь напрямую, а сохраняешь номер под именем и потом набираешь по имени. Можно поменять, кому привязан контакт, не меняя код, который «звонит».

Ещё важно: в один делегат можно подписать несколько методов (multicast), и при вызове отработают все по очереди:

Action hello = () => Console.WriteLine("Привет");
hello += () => Console.WriteLine("Пока");
hello(); // выведет обе строки

Это как раз то, на чём держатся события.

Ваш ответ

Войдите, чтобы ответить на вопрос.
Поддержать проект