1. Вступ
Можливо, ви цього ще не знаєте, але одне з улюблених питань на співбесідах — «Що ви знаєте про лямбда-вирази?». Чому про них питають? Бо це дуже зручний і «модний» прийом у C#, що дає змогу писати менше коду й робити його виразнішим. Якщо анонімні методи — це як писати листа від руки, то лямбда-вирази — як надсилати повідомлення у месенджері: швидко, компактно й інколи навіть зі смайликами (ну, майже).
Лямбда-вирази з’явилися у C# з версії 3.0, і відтоді вони повсюдні: у LINQ, обробниках подій, потоках, колекціях і навіть у бібліотеках штучного інтелекту для .NET.
Лямбда-вираз — це спосіб оголосити метод просто у тілі коду, «на місці», без імені, надкоротко й зрозуміло. Базовий синтаксис завжди виглядає так:
(параметри) => вираз_або_блок_коду
Цю «стрілочку» => називають лямбда-оператором або просто «стрілкою».
Невеличка аналогія
Згадайте, як ви записуєте рецепт: «Взяти яблуко, порізати його, покласти в миску».
У C# це було б:
(яблуко) => порізати(яблуко)
2. Перероблюємо анонімний метод на лямбду
Припустімо, у нас є делегат:
delegate int SquareDelegate(int x);
Анонімний метод виглядав би так:
SquareDelegate sq = delegate(int x) {
return x * x;
};
А тепер те саме через лямбда-вираз:
SquareDelegate sq = (int x) => { return x * x; };
Але C# вміє виводити типи, тож можемо ще скоротити:
SquareDelegate sq = x => x * x;
Вражаюча компактність!
Порівняння зі «звичайним» методом і анонімною функцією
| Спосіб | Оголошення | Де можна використовувати | Мінуси |
|---|---|---|---|
| Іменований метод | У класі | Скрізь | Потрібне імʼя, більше коду |
| Анонімний метод | У коді | Лише з делегатами | Громіздкіший синтаксис |
| Лямбда-вираз | У коді | Скрізь із делегатами | Іноді тип неочевидний |
3. Синтаксис лямбда-виразу: варіації
Параметри
Без параметрів:
Action hello = () => Console.WriteLine("Привіт, світ!");
Один параметр (можна опустити дужки):
Func<int, int> inc = x => x + 1;
Кілька параметрів (потрібні дужки):
Func<int, int, int> sum = (a, b) => a + b;
Тіло лямбди
Один вираз — без фігурних дужок і return:
x => x * x
Блок коду — фігурні дужки, потрібен return:
(x, y) =>
{
int z = x + y;
return z * z;
}
Типи параметрів
Найчастіше тип вказувати не потрібно — компілятор здогадається. Але якщо хочете — будь ласка:
(x, y) => x + y // Компілятор сам виводить типи.
(int x, int y) => x + y // Можна явно.
4. Нюанси та більш реальні приклади
Використання з колекціями
Пам’ятаєте наш навчальний міні‑застосунок (наприклад, список користувачів)? Припустімо, у нас є масив чисел:
int[] numbers = { 1, 2, 3, 4, 5 };
Треба обрати лише парні числа:
var evenNumbers = numbers.Where(n => n % 2 == 0);
Тут Where — метод-розширення LINQ, а умова — наш лямбда-фільтр.
Передача в метод
Припустімо, у нас є метод-делегат:
public delegate bool Filter(int number);
public static int[] FilterNumbers(int[] data, Filter predicate)
{
var result = new List<int>();
foreach (var n in data)
if (predicate(n))
result.Add(n);
return result.ToArray();
}
Тепер передаємо лямбда-вираз:
int[] evens = FilterNumbers(numbers, n => n % 2 == 0);
Лямбда як обробник подій
button.Click += (sender, args) => Console.WriteLine("Кнопку натиснуто!");
5. Лямбда-вирази і стандартні узагальнені делегати
Лямбди важко уявити без Func<>, Action<> і Predicate<>. Це спеціальні типи делегатів:
- Action — нічого не повертає.
- Func — повертає значення.
- Predicate — повертає bool, зазвичай для фільтрації.
Приклад з Action:
Action<string> log = message => Console.WriteLine(message);
log("Це повідомлення через лямбду!");
Приклад з Func:
Func<int, int, int> multiply = (a, b) => a * b;
int product = multiply(3, 5); // 15
Приклад з Predicate:
Predicate<int> isNegative = n => n < 0;
bool test = isNegative(-7); // true
6. Лямбди з кількома виразами: коли потрібен блок
Якщо лямбда має виконувати кілька операцій, використовуйте фігурні дужки й явний return:
Func<int, int, string> describeSum = (a, b) =>
{
int sum = a + b;
return $"Сума: {sum}";
};
Без return компілятор обуриться (але до ладу не пояснить чому — просто повідомить, що «не всі шляхи повертають значення»).
7. Повернення void: Action
Коли лямбда нічого не повертає, використовуйте Action:
Action greet = () => Console.WriteLine("Посміхайтеся — код компілюється!");
Лямбда може містити скільки завгодно інструкцій:
Action<int> printSquare = x =>
{
int sq = x * x;
Console.WriteLine($"Квадрат числа {x} дорівнює {sq}");
};
8. Обмеження та типові помилки
Іноді хочеться написати лямбду дуже довільно, але компілятор не завжди з цим погоджується.
Не можна оголошувати змінну з тим самим імʼям, що й захоплена ззовні.
Слідкуйте за типами: якщо сигнатура делегата й лямбди не збігається, буде помилка.
Повернення значення обов’язкове, якщо делегат його вимагає.
У складних лямбдах не забувайте про фігурні дужки. Один вираз — без дужок і return. Кілька інструкцій — дужки й return.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ