C# Lambda expression

01 definition

Lambda expression is actually an unnamed method used to replace a delegate instance

The compiler will convert the lambda Expression into one of the following two: a delegate instance and an Expression tree. The type is Expression, which represents the code in the lambda Expression in the traversable object model. It allows lambda expressions to be interpreted at run time.


delegate int Transformer(int i);
Transformer sqr = x => x * x;
Console.WriteLine(sqr(3));   //9

In fact, the compiler will parse the Lambda expression by writing a private method, and then move the code of the expression into the method.

02 use

//(parameter) = > expression or statement block
(parameters) => expression-or-statement-block

If there is only one parameter and the type can be inferred, the parentheses of the parameter can be omitted

lambda expressions and delegates

  • The parameters of each lambda expression correspond to the parameters of the delegate
  • The type of the expression corresponds to the return type of the delegate

Statement block

The code of a lambda expression can also be a statement block

x => {return x*x;};

Func and Action delegation

Lambda expressions are typically used with Func and Action delegates

Func<int,int> sqr = x => x*x;
Func<string,string,int> totalLength = (s1,s2) => s1.Length + s2.Length;
int tatal = totalLength("hello","world"); // total is 10

Displays the parameter type of the specified lambda expression

Sometimes the parameter type cannot be inferred. At this time, the parameter type of the specified lambda expression should be displayed

void Foo<T> (T x){}
void Bar<T> (Action<T> a){}
Bar(x=> Foo(x)); //What type is x?
Bar((int x) => Foo(x));
Bar<int>(x=> Foo(x)); //Specify type
Bar<int>(Foo(x)); //Usage group

Capture external variables

lambda expressions can refer to local variables and parameters of the method

static void main(){
	int f = 2;
	Func<int,int> multi = x => x*f;
	Console.WriteLine(multi(3));   //6

In the above example, f is called the captured variable, and lambda expressions that capture external variables are called closures (JavaScript also has the concept of closures)

The captured variables are calculated only when the delegate is actually called, rather than defined. The above example is slightly modified

static void main(){
	int f = 2;
	Func<int,int> multi = x => x*f;
	f = 10;
	Console.WriteLine(multi(3));   //The output is 30

lambda expressions can also update captured variables

int i = 0;
Func<int> add = ()=> i++;
Console.WriteLine(add());   //0
Console.WriteLine(add());   //1
Console.WriteLine(i);   //2

The life cycle of the captured variable is extended to be the same as that of the delegate

static Func<int> add(){
	int i = 0; //This variable is destroyed only after you know that the following lambda expression is not used
	return ()=> i++;

static void main(){
    Func<int> f = add();
    Console.WriteLine(f());   //0
	Console.WriteLine(f());   //1

Local variables within lambda expressions

Local variables instantiated in lambda expressions are unique to each invocation of a delegate instance.

static Func<int> add(){
	return () => {
		int i = 0;
		return i++;

static void main(){
    Func<int> f = add();
    Console.WriteLine(f());   //0
	Console.WriteLine(f());   //0

Capture iteration variables

When capturing the iteration variable of the for loop, C# will treat this variable as a variable defined outside the loop, which means that each iteration captures the same variable

Action[] actions = new Action[3];

for(int i=0;i<3;i++){
	actions[i] = () => Console.WriteLine(i);

foreach(Action a in actions) a(); //3. Understanding is the same as capturing external variables

How to solve the above problems? Minor change

Action[] actions = new Action[3];

for(int i=0;i<3;i++){
	int k = i;	//Each lambda expression captures a different k. you can see the scope of k, which is very similar to multithreading
	actions[i] = () => Console.WriteLine(k);

foreach(Action a in actions) a(); //0 1 2

Note: foreach

Difference between C#4 and C#5 +

Action[] actions = new Action[3];
int i=0;
foreach(char c in 'abc'){
	actions[i++] = () => Console.WriteLine(c);

foreach(Action a in actions) a(); //The C#4 output is ccc and the C#5 + output is abc

lambda expressions vs native methods

Native methods are a new feature of C#7.

There are many functional repetitions between it and Lambda expression, but it has three advantages:

• recursion can be done simply and clearly

• there is no need to specify the delegate type (that pile of code)

• slightly lower performance overhead

The local method is more efficient because it avoids indirect calls of delegates (CPU cycles, memory allocation). Local methods can also access the local variables of the method, and there is no need for the compiler to hoist the captured variables to hidden classes.

Anonymous method vs Lambda expression

Anonymous methods are similar to Lambda expressions, but lack the following three features:

  • Implicit type parameter
  • Expression syntax (only statement blocks)
  • The ability to compile the expression tree by assigning values to Expressions


delegate int Add(int i);
Add add = delegate (int x){return x*x}; //Anonymous Methods 
Console.WriteLine(add(3)); //9
Add add = x => x*x; //Lambda expression

Therefore, anonymous methods are gradually not used

Tags: .NET

Posted by Diego17 on Fri, 15 Apr 2022 20:21:09 +0930