Что такое лямбда выражения в С#


Лямбда-выражения в C# — это краткая форма объявления анонимных методов (методов без имени), которые можно использовать для определения делегатов или выражений LINQ. Лямбда-выражения были введены в C# 3.0 и играют ключевую роль в функциональном стиле программирования внутри языка.

📌 Общий синтаксис

(parameters) => expression

или для блока кода:

(parameters) => { statements }

📌 Пример простого лямбда-выражения

Func<int, int> square = x => x \* x;
Console.WriteLine(square(5)); // 25

Здесь:

  • Func<int, int> — делегат, который принимает int и возвращает int.

  • x => x * x — лямбда-выражение, которое принимает параметр x и возвращает x * x.

📌 Использование с делегатами

Лямбда-выражения позволяют создать анонимные методы, которые легко передаются как параметры:

List&lt;int&gt; numbers = new List&lt;int&gt; { 1, 2, 3, 4, 5 };
var evens = numbers.Where(n => n % 2 == 0).ToList(); // \[2, 4\]

В данном примере n => n % 2 == 0 — это предикат, переданный в метод Where.

📌 Использование с Action, Func и Predicate

  • Action — ничего не возвращает:
Action&lt;string&gt; greet = name => Console.WriteLine($"Hello, {name}");
greet("Alice");
  • Func<T, TResult> — возвращает значение:
Func&lt;int, int&gt; doubleIt = n => n \* 2;
Console.WriteLine(doubleIt(6)); // 12
- Predicate&lt;T&gt;  возвращает bool:    
Predicate&lt;int&gt; isPositive = n => n > 0;
Console.WriteLine(isPositive(-5)); // false

📌 Множественные параметры

Func&lt;int, int, int&gt; add = (a, b) => a + b;
Console.WriteLine(add(3, 7)); // 10

📌 Блочные лямбда-выражения

Если тело выражения содержит несколько строк, используются фигурные скобки:

Func&lt;int, int, int&gt; multiplyAndAdd = (a, b) =>
{
int product = a \* b;
return product + 10;
};
Console.WriteLine(multiplyAndAdd(2, 3)); // 16

📌 Захват переменных из внешнего контекста (closure)

Лямбда-выражения могут использовать переменные из окружающей области видимости:

int factor = 10;
Func&lt;int, int&gt; multiply = x => x \* factor;
Console.WriteLine(multiply(5)); // 50

Если factor изменится — изменится и результат:

factor = 2;
Console.WriteLine(multiply(5)); // 10

📌 Лямбда и LINQ

Лямбда-выражения активно применяются в LINQ-запросах:

var numbers = new List&lt;int&gt; { 1, 2, 3, 4, 5 };
var squared = numbers.Select(x => x \* x).ToList(); // \[1, 4, 9, 16, 25\]

📌 Лямбда-выражения и Expression Trees

Когда используется Expression<Func, компилятор создаёт дерево выражений, а не просто метод:

Expression&lt;Func<int, bool&gt;> expr = x => x > 10;

Такое дерево может быть разобрано, интерпретировано или преобразовано, что особенно полезно, например, в Entity Framework при формировании SQL-запросов.

📌 Сравнение с анонимными методами

До появления лямбд существовали анонимные методы:

Func&lt;int, int&gt; square = delegate (int x) {
return x \* x;
};

Лямбды — это более короткий и читаемый способ записи того же самого, к тому же они могут быть как выражением, так и блоком кода.

📌 Типизация

Тип параметров в лямбда-выражениях обычно выводится компилятором:

numbers.ForEach(n => Console.WriteLine(n)); // Тип n  int

Можно явно указать тип, но это делается редко:

numbers.ForEach((int n) => Console.WriteLine(n));

📌 Ограничения

  • Нельзя использовать goto, break, continue за пределами лямбда-тела.

  • Внутри лямбды нельзя использовать ref или out параметры напрямую.

  • Лямбда не может иметь атрибутов (в отличие от обычного метода).

📌 Примеры сложного применения

Фильтрация коллекции по нескольким условиям:

var filtered = items.Where(item =>
item.IsActive &&
item.Quantity > 0 &&
item.Name.StartsWith("A"));

Сортировка по нескольким полям:

var sorted = users.OrderBy(u => u.LastName).ThenBy(u => u.FirstName);

📌 Лямбды внутри событий

button.Click += (sender, args) => {
Console.WriteLine("Кнопка нажата!");
};

📌 Передача лямбд как параметров

void Process(Func&lt;int, int&gt; operation)
{
Console.WriteLine(operation(10));
}
Process(x => x + 5); // 15

📌 Лямбда внутри методов

Лямбды часто используются для написания компактного и читабельного кода без необходимости создавать отдельные методы. Это упрощает разработку, особенно при работе с LINQ, событиями, обработкой коллекций и функциональными интерфейсами.