Что такое делегат?csharp-20

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

Основные характеристики делегатов

  1. Типобезопасность - компилятор проверяет соответствие сигнатур
  2. Ссылочный тип - наследуется от System.MulticastDelegate
  3. Поддержка цепочек вызовов (multicast delegates)
  4. Используются для событий и callback-ов

Объявление и использование делегатов

1. Объявление типа делегата

// Объявляем тип делегата
public delegate int MathOperation(int a, int b);

2. Создание экземпляра делегата

// Методы, совместимые с делегатом
int Add(int x, int y) => x + y;
int Subtract(int x, int y) => x - y;

// Создание экземпляров делегата
MathOperation operation = Add;
int result = operation(5, 3); // 8

operation = Subtract;
result = operation(5, 3); // 2

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

C# предоставляет готовые шаблоны делегатов:

  1. Action - для методов без возвращаемого значения

    Action<string> log = message => Console.WriteLine(message);
    log("Hello, Action!");
    
  2. Func - для методов с возвращаемым значением

    Func<int, int, int> multiply = (x, y) => x * y;
    int product = multiply(4, 5); // 20
    
  3. Predicate - для методов, возвращающих bool

    Predicate<string> isLong = s => s.Length > 10;
    bool longString = isLong("Hello, Predicate!"); // true
    

Multicast делегаты

Делегаты могут содержать несколько методов в цепочке вызовов:

Action processor = () => Console.Write("A");
processor += () => Console.Write("B");
processor += () => Console.Write("C");

processor(); // Выведет "ABC"

Применение делегатов

  1. Обратные вызовы (callbacks)

    public void LongRunningOperation(Action callback)
    {
        // Долгая операция...
        callback();
    }
    
  2. События (events)

    public class Button
    {
        public event Action Clicked;
    
        public void Click() => Clicked?.Invoke();
    }
    
  3. Стратегии (strategy pattern)

    public void ProcessData(int[] data, Func<int, int> transform)
    {
        for(int i = 0; i < data.Length; i++)
            data[i] = transform(data[i]);
    }
    

Делегаты vs Интерфейсы

КритерийДелегатыИнтерфейсы
ПривязкаПоздняя (runtime)Ранняя (compile-time)
Количество методовОдин методМножество методов
ПроизводительностьБыстрее вызовМедленнее вызов
ГибкостьЛегко менять поведениеТребует новых классов

Современные альтернативы

  1. Лямбда-выражения - компактный синтаксис

    Func<int, int> square = x => x * x;
    
  2. Локальные функции (C# 7.0+)

    void Process()
    {
        int Add(int a, int b) => a + b;
        var result = Add(2, 2);
    }
    

Резюмируем

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