Как вы используете делегаты в C# на практике?

«Как вы используете делегаты в C# на практике?» — вопрос из категории C# Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Делегаты — это фундаментальный механизм C#, который я активно использую для реализации обратных вызовов (callbacks), событий (events) и паттернов, таких как Strategy.

1. Базовое применение и встроенные типы: Вместо объявления кастомных делегатов чаще использую встроенные обобщенные типы:

  • Action<T>: Делегат для метода, который что-то делает, но не возвращает значение (void).
  • Func<T, TResult>: Делегат для метода, возвращающего значение.
  • Predicate<T>: Частный случай Func<T, bool> для проверки условия.

    // Action для логирования
    Action<string> logMessage = (message) => Console.WriteLine($"[LOG]: {message}");
    logMessage("Operation started");
    
    // Func для преобразования
    Func<int, int, int> add = (x, y) => x + y;
    int sum = add(5, 3); // 8
    
    // Predicate для фильтрации в коллекции
    Predicate<string> isLong = (text) => text.Length > 10;
    List<string> words = new List<string> { "hello", "internationalization" };
    var longWord = words.Find(isLong); // "internationalization"

2. Реализация паттерна Стратегия (Strategy Pattern):

   public class DataProcessor
   {
       private Func<string, string> _exportStrategy;

       public void SetExportStrategy(Func<string, string> strategy)
       {
           _exportStrategy = strategy;
       }

       public string ProcessAndExport(string data)
       {
           // ... обработка данных ...
           return _exportStrategy?.Invoke(data) ?? data;
       }
   }

   // Использование
   var processor = new DataProcessor();
   processor.SetExportStrategy(data => $"JSON: {JsonSerializer.Serialize(data)}");
   var result = processor.ProcessAndExport("test");

3. События (Events): События — это надстройка над делегатами, обеспечивающая безопасную подписку и отписку.

   public class OrderService
   {
       public event EventHandler<OrderCreatedEventArgs> OrderCreated;

       public void CreateOrder(Order order)
       {
           // ... создание заказа ...
           OnOrderCreated(new OrderCreatedEventArgs(order.Id));
       }

       protected virtual void OnOrderCreated(OrderCreatedEventArgs e)
       {
           OrderCreated?.Invoke(this, e); // Проверка на null (thread-safe)
       }
   }

4. LINQ и асинхронность: Все методы LINQ (Where, Select, OrderBy) принимают делегаты (Func<T, bool> и т.д.). Асинхронные методы также используют делегаты, например, Task.Run(Action).