🔷 C#

دوال لامدا والأسلوب الوظيفي في C# (.NET): دليل مفصل

What is it and why? (a real-life analogy)

Imagine you are a chef in a restaurant. You have a standard set of tools: knives, frying pans, pots. But every day different visitors come with different wishes. One asks "cut the vegetables into cubes," another "cut them into strips," a third "cut them into circles." Instead of buying a separate machine for each cutting method, you simply take a universal knife and say: "Here is a knife, and how exactly to cut — I'll decide on the spot, depending on the order."

In programming, a lambda function is that very "universal knife." It is a small function that you create right on the spot when you need it, and use it immediately. It doesn't need a name, it doesn't need to be declared in advance elsewhere in the code. You simply say: "Here's what needs to be done with each element of this list" — and describe the action right in the line where it is executed.

Why is this needed? Imagine you have a list of numbers, and you want to:

  • keep only the even ones;
  • multiply each number by 2;
  • sort in descending order.

Without lambda functions, you would have to write three separate methods, give them names, and call them. With lambdas, this is done in three short lines. The code becomes shorter, clearer, and you spend less time switching between different parts of the program.

Important: A lambda function is not magic, but simply a convenient syntax. Inside the computer, it works the same as a regular function. You just write it faster and more compactly.

Functional style is an approach where we describe what needs to be done with the data, rather than how to do it step by step. Instead of a loop with a counter variable, we say: "Take each element and apply this action to it." Lambdas are the main tool of this style in C#.

Theory: how it works from the inside

To understand lambdas, you need to understand two things: delegates and expression trees. Don't be scared — I'll explain in simple terms.

Delegates — these are "boxes for functions"

A delegate is a data type that can store a reference to a method. Imagine a remote control. The remote has a button. You can "assign" any action to this button: turn on the light, open the door, start the music. The button itself is the delegate. And what happens when you press it is the method that you "attached" to it.

In C#, there are built-in delegates, the most popular ones are:

Delegate What it takes What it returns Usage example
Func<T, TResult> One or more parameters A value Converting a number to a string
Action<T> One or more parameters Nothing (void) Outputting an element to the screen
Predicate<T> One parameter Always bool Checking a condition (filtering)

A lambda function is simply a convenient way to create a method and immediately "package" it into such a delegate.

Expression trees — these are "blueprints" of lambdas

Sometimes a lambda needs not to be executed, but to be analyzed. For example, to translate it into an SQL query for a database (this is done by Entity Framework and other ORMs). In such cases, the lambda turns not into a delegate, but into an expression tree — a data structure that describes what the lambda does, but does not execute it.

A simple example: the lambda x => x > 5 as an expression tree will store the information: "there is a parameter x, there is a comparison operation 'greater than', there is a constant 5". This allows the library to read this "blueprint" and, for example, write SQL: WHERE x > 5.

Remember: If the lambda works with in-memory collections (List, Array) — it's a delegate. If it works with IQueryable (database) — it's an expression tree. The difference is important because some constructs (like assignment) cannot be used in an expression tree.

Closures — the "memory" of a lambda

A lambda can use variables that are declared outside its body. This is called a closure. The lambda "remembers" the value of these variables at the moment of its creation.

Example: you declared a variable int multiplier = 10;, and then created a lambda x => x * multiplier. Even if you later change multiplier, the lambda will use the value that was "captured" at the moment of creation (if it is not a reference type).

Syntax in C# (.NET): all forms and variants

A lambda function in C# is written using the => operator (arrow). On the left are the input parameters, on the right is the function body. There are several forms of notation.

1. Full form with a code block

// The most complete form: parameters in parentheses, body in curly braces
Func<int, int, int> addition = (int a, int b) =>
{
    int result = a + b;
    return result;
};

int sum = addition(5, 3); // result: 8

2. Shortened form (single expression)

// If the body consists of a single expression, curly braces and return are not needed
Func<int, int, int> addition = (a, b) => a + b;

int sum = addition(5, 3); // result: 8

3. One parameter — without parentheses

// If there is only one parameter, parentheses can be omitted
Func<int, int> double