匿名方法和Lambda表达式


匿名方法和Lambda表达式

1、匿名方法

在C#2.0版本中引入了匿名方法,匿名方法与具名方法(即普通的方法)相对

简单示例:

delegate void MyDelegate(int x); //声明一个委托类型

void Main()
{
	MyDelegate del = delegate(int x)
	{
		Console.WriteLine($"匿名方法输出值:{x}");	
	};
	
	del(20);
}

使用场景

  1. 给初始化委托变量
  2. 给组合委托赋值
  3. 给委托增加方法

语法

匿名方法必须与关联的委托保持格式一致,也就是返回值和参数需要相同,注意语句块后面是有分号的,不要漏掉

delegate(参数列表) {语句块};

返回值

匿名方法不会显示地声明返回值,但是返回值要和对应的委托保持一致。如果委托没有返回值,即为void时,匿名方法则不能有返回值;如果委托有返回值,则匿名函数需要在语句块中返回对应类型的值。

delegate int MyDelegate(int x); //声明一个委托类型

void Main()
{
	MyDelegate del = delegate(int x)
	{
		Console.WriteLine($"匿名方法输出值:{x}");	
		return (x + 10);
	};    
}

参数列表

参数列表要和声明的委托保持一致,也就是参数的个数、类型及位置。

当委托没有out参数或匿名方法没有输入参数时,则可以省略匿名方法的参数列表。当匿名方法不需要输入参数时,这种情况下参数列表可以和委托不一致了,但同时在调用委托时,传入的参数也不会起到作用。

delegate int MyDelegate(int x); //声明一个委托类型

void Main()
{
	MyDelegate del = delegate
	{
		Console.WriteLine($"匿名方法不需要使用输入参数");	
		return 10;
	};
	
	del(20);
}    

如果在委托类型的声明中,参数列表使用了params参数,则匿名方法的参数列表会忽略params关键字的作用。

外部变量的捕获

在匿名方法中使用方法块外部的变量很简单,可以直接使用

delegate int MyDelegate(int x); //声明一个委托类型

void Main()
{
	int val = 20;
	MyDelegate del = delegate
	{
        //捕获匿名方法外部的val变量
		Console.WriteLine($"匿名方法输出:{val+10}");	
		return 10;
	};
	
	del(20);
}    

输出:

匿名方法输出:30

捕获变量的生命周期会在委托被调用时得到扩展

MyDelegate del;
	
{
    int val = 20; //val变量的作用域和生命周期在此代码块中

    del = delegate
    {
        Console.WriteLine($"匿名方法输出:{val + 10}");
        return 10;
    };
}

del(20); //委托调用时,由于匿名方法捕获了val变量,val变量的生命周期在此得到延续

2、Lambda表达式

在C#3.0中引入Lambda,简化了匿名方法,用来替代匿名方法。lambda表达式相比匿名方法,不需要使用delegate关键字,并且有更精简的写法,易于理解也提高了效率。

使用场景

和匿名方法一样,作为委托delegate的初始化方法或给委托增加方法

还可以用在属性的get、set中

语法格式

Lambda运算符=>,读作 goes to

参数列表 => 方法块

示例:

delegate void MyDelegate(int x); //声明一个委托类型

void Main()
{
	MyDelegate del;
	del = delegate (int x) { Console.WriteLine($"匿名方法输出:{x}"); }; //匿名方法
	del = (int x) => { Console.WriteLine($"Lambda表达式输出:{x}"); }; //lambda表达式
	del(20);
}

带返回值

delegate int MyDelegate1(int x); //声明一个委托类型

void Main()
{
	MyDelegate1 del1;
	del1 = x => 
	{
		Console.WriteLine($"Lambda表达式输出:{x}");
		return 10;
	};
	
	del1(100);
}

参数列表

  1. 参数列表一般来说格式要和委托类型保持一致
  2. 没有参数时,必须要用空的()来表示
  3. 只有一个参数时,可以省略()
  4. Lambda表达式中参数类型可以省略,除非委托参数中有ref和out修饰的参数,则不可省略

参数列表带有类型称为显示类型,没有类型称为隐式类型

delegate void MyDelegate(int x); //声明一个委托类型

void Main()
{
	MyDelegate del;
	del = (int x) => { Console.WriteLine($"Lambda表达式输出:{x}"); };
	del = (x) => { Console.WriteLine($"Lambda表达式输出:{x}"); }; //省略类型
	del = x => { Console.WriteLine($"Lambda表达式输出:{x}"); }; //省略()
	del = x => Console.WriteLine($"Lambda表达式输出:{x}"); //只有一条语句,也可以放return的表达式

	del(20);
}

多个参数

delegate int MyDelegate2(int x, int y, int z); //声明一个委托类型

void Main()
{
	MyDelegate2 del2, del3, del4;
	del2 = (int x, int y, int z) =>
	{
		Console.WriteLine($"x = {x},  y = {y},  z = {z}");
		return 20;
	};

	del3 = (x, y, z) => x + y + z; //省略参数类型,一个语句作为return表达式 
	//del4 = x, y, z => x + y + z; //多个参数时无法省略()
	
	del2(3, 5, 7);
	Console.WriteLine(del3(3, 5, 7));
}

输出

x = 3, y = 5, z = 7
15