Как лямбда-выражение связано с делегатом в C#?

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

Ответ

Лямбда-выражение — это компактный синтаксис для создания анонимного метода, который может быть неявно преобразован в экземпляр делегата или в дерево выражений (Expression<T>). Компилятор C# автоматически генерирует код делегата на основе лямбды.

Практический пример:

// Лямбда-выражение присваивается делегату типа Func<int, int, int>
Func<int, int, int> add = (x, y) => x + y;
int result = add(5, 3); // result = 8

// Та же лямбда может быть использована для другого совместимого делегата
Action<int, int> printSum = (x, y) => Console.WriteLine(x + y);
printSum(5, 3); // Вывод: 8

Ключевые моменты связи:

  1. Автоматическое преобразование: Компилятор выводит тип делегата из контекста. Сигнатура лямбды (типы параметров и возвращаемого значения) должна соответствовать сигнатуре делегата.
  2. Замыкания: Лямбда может захватывать ("видеть") локальные переменные и параметры метода, в котором она объявлена. Для этого компилятор создает скрытый класс-замыкание.
    int multiplier = 2;
    Func<int, int> multiplierFunc = x => x * multiplier; // Захват переменной multiplier
  3. Деревья выражений: Если лямбда присваивается типу Expression<TDelegate>, компилятор строит дерево выражений (данные о коде), а не исполняемый IL-код. Это основа таких технологий, как LINQ to SQL.
    // Дерево выражений, а не делегат
    Expression<Func<int, int, int>> expression = (x, y) => x + y;

    Использование лямбд вместо явного создания делегатов через new DelegateType() делает код значительно чище и читабельнее.