Для чего нужны делегаты в C#?

129
03 января 2021, 16:20

Разбираюсь в c# в частности с делегатами, возник вопрос зачем нужны делегаты если можно создать экземпляр класса и вызвать метод.

Экземпляр класса

class MainClass
{
    public string  Print3(string s)
    {
        return s + "hello bro";
    }
    public static void Main()
    {
        MainClass m = new MainClass();
        m.Print3...
    }
}

Делегат

delegate string Print2(string s);
class MainClass
{
    static string  Print3(string s)
    {
        return s + "hello bro";
    }
    public static void Main()
    {
        Print2 p = new Print2(Print3);
        string s = p("hello");
    }
}
Answer 1

Вопрос: Можно ли обойтись без делегатов?

Ответ: Да. Java, можно сказать, обходится без них, до версии 8 так и аналогов никаких не было. Да и во многих других языках аналогов нет.

Вопрос: Можно ли код, который использует делегаты, переписать без делегатов?

Ответ: Да. Например, в той же Java, до версии 8, всегда когда нужно было привязать слушатель к событию нужно было объявить класс. Выглядело это примерно так:

button.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent clickevent) {
        System.out.println("Button Clicked");
  }
});

Вопрос: Для чего нужны делегаты?

Ответ: Это синтаксический сахар. Они позволяют писать код короче.

Например, аналог кода выше на C#:

button.Click += (s, e) => Console.WriteLine("Button clicked");

Делегаты тесно связаны с другими элементами языка:

  • на них реализованы операторы сложения и вычитания;
  • они работают с методами, анонимными методами и лямбда-выражениями;
  • привязываются к событиям.

Все это можно при желании реализовать самому через классы и интерфейсы, но этот функционал расширяет возможности языка, позволяет писать более короткий код.

Если можете написать код без делегатов — пишите. Но если тот же код можно написать быстрее и проще с делегатами было бы странно их не использовать.

Вообще, без большей части функционала языка можно обойтись: код, в котором используется наследование, можно переписать без него; классы можно переписать на процедурах и т.д. Любой код на C# можно переписать на ассемблере без потери производительности и функционала. Просто кода будет намного больше. В Brainfuck всего 8 инструкций и любой код на C# теоретически можно переписать на нем. Разница в производительности если будет, то она скорее будет связана с поддержкой оптимизаций на уровне ОС и процессоров чем с возможностями языка.

P.S. Последний раз про Java: в версии 8 ввели лямбда-выражения не вводя при этом понятия «делегат» и «событие» на уровне языка. Вместо делегатов используются интерфейсы. Из-за отстутствия поддержки на уровне языка операторы на них не определены и объявление выглядит чуть более громоздко, но возможности те же.

Answer 2

Один из примеров, когда без делегатов вовсе не обойтись - взаимодействие с кодом на процедурных языках программирования, который оперирует указателями на функции. Например, см. данный ответ, в котором определяется делегат

delegate IntPtr KeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

который передается в неуправляемую функцию SetWindowsHookEx в качестве параметра HOOKPROC. Исключительно на классах (через шаблон "Наблюдатель") это не реализовать.

Answer 3

С помощью делегатов можно передать ссылку на метод или сам метод как параметр.

Например:

User GetUser(uint id, Action<Exception> onError)

Этот метод возвращает объект User, и если произошла ошибка то выполняет НАШ код передавая в него Exception

try {} catch(Exception e) {
OnError?.Invoke(e);
}

Конкретно в Вашем случае можно не создавать новый делегат, а воспользоваться встроенным Action.

void Print(Action<string> print2) {
    print2?.Invoke("myMessage");
}

Вызвать такой метод можно следующим образом:

void Print2((e) => { Console.WriteLn(e); }
READ ALSO
Ошибка Failed to open the referenced table

Ошибка Failed to open the referenced table

Не получается настроить references в MySQL, не понимаю что делаю не правильно

244
relation does not exist

relation does not exist

3-й день мучаюсь с данной проблемойНа heroku имеется БД MySQL

147