Lambda表达式是一种匿名函数,可以用来创建委托或表达式树,它使用 => 运算符来指定输入参数和表达式或语句块。Lambda表达式可以简化匿名委托的使用,减少开发中需要编写的代码量。Lambda表达式可以分为表达式Lambda和语句Lambda,前者返回表达式的结果,后者可以包含多条语句。Lambda表达式还可以使用async和await关键字来创建包含异步处理的lambda表达式和语句。
在本文中,我们将介绍c# lambda表达式的5种典型的高频使用方法,分别是:
使用lambda表达式作为委托或事件处理程序
使用lambda表达式作为LINQ查询的谓词或选择器
使用lambda表达式作为Task.Run或Task.Factory.StartNew的参数
使用lambda表达式作为表达式树
使用lambda表达式作为异步方法
在介绍这些使用方法之前,我们先回顾一下c#中委托的演变过程,以及lambda表达式的基本语法和特点。
c#中委托的演变过程
委托是一种引用类型,它可以封装一个具有特定参数和返回值类型的方法。委托可以用来实现回调函数、事件处理程序、匿名方法等功能。
在c# 1.0中,要创建一个委托实例,需要先定义一个委托类型,然后使用一个已经存在的方法来初始化委托。例如:
//定义一个委托类型delegateintCalculateHandler(int x, int y);
//定义一个符合委托类型签名的方法privateintSum(int x, int y)
{
return x + y;
}
//创建一个委托实例,并用Sum方法初始化
CalculateHandler sumHandler = new CalculateHandler(Sum);
//调用委托实例
Console.WriteLine(sumHandler(1, 2)); //输出结果3
这种方式需要显式地定义一个委托类型和一个方法,比较繁琐。
在c# 2.0中,引入了匿名方法的概念,可以在创建委托实例时直接编写未命名的内联语句块,而不需要单独定义一个方法。例如:
//定义一个委托类型delegateintCalculateHandler(int x, int y);
//创建一个委托实例,并用匿名方法初始化
CalculateHandler sumHandler = delegate(int x, int y)
{
return x + y;
};
//调用委托实例
Console.WriteLine(sumHandler(1, 2)); //输出结果3
这种方式省去了定义一个方法的步骤,但仍然需要定义一个委托类型,并且语法比较冗长。
在c# 3.0中,引入了lambda表达式,这是一种更简洁和更具表现力的匿名函数。lambda表达式可以直接表示为委托或表达式树的代码,并且可以自动推断输入参数的类型。例如:
//定义一个委托类型delegateintCalculateHandler(int x, int y);
//创建一个委托实例,并用lambda表达式初始化
CalculateHandler sumHandler = (x, y) =>
return x + y;
};
//调用委托实例
Console.WriteLine(sumHandler(1, 2)); //输出结果3
这种方式不需要定义一个委托类型,也不需要使用delegate关键字,只需要使用 => 运算符来指定输入参数和表达式或语句块。lambda表达式的语法更加简洁和优雅。
lambda表达式的基本语法和特点
lambda表达式的基本语法如下:
(input-parameters) => expression-or-statement-block
其中,=> 运算符读作“goes to”,表示将输入参数映射到表达式或语句块。输入参数可以有0个、1个或多个,如果有多个参数,需要用逗号分隔,并用括号括起来。如果只有一个参数,可以省略括号。如果没有参数,必须使用空括号。例如:
() => Console.WriteLine("Hello"); //没有参数
x => x * x; //一个参数
(x, y) => x + y; //两个参数
表达式或语句块可以是一个单行的表达式,也可以是一个多行的语句块。如果是一个单行的表达式,lambda表达式会返回表达式的结果。如果是一个多行的语句块,需要用大括号括起来,并且可以使用return语句来返回值。例如:
x => x * x; //单行表达式,返回x的平方
(x, y) =>
{
int result = x + y; //多行语句块return result; //使用return语句返回值
};
lambda表达式的特点有以下几点:
lambda表达式可以自动推断输入参数的类型,不需要显式地指定类型。例如:
//不需要指定x和y的类型
(x, y) => x + y;
lambda表达式可以根据上下文来确定其委托类型或表达式树类型。例如:
//根据委托类型推断lambda表达式的类型
Func add = (x, y) => x + y;
Action print = s => Console.WriteLine(s);
//根据事件处理程序推断lambda表达式的类型
button.Click += (sender, e) => Console.WriteLine("Button clicked");
//根据LINQ查询推断lambda表达式的类型var evenNumbers = numbers.Where(n => n % 2 == 0);
lambda表达式可以捕获外部变量,并在其主体中使用它们。这些变量被称为捕获变量,它们会在lambda表达式创建时被复制,并在lambda表达式执行时被更新。例如:
int factor = 2;
Func multiplier = n => n * factor;
Console.WriteLine(multiplier(3)); //输出6
factor = 3;
Console.WriteLine(multiplier(3)); //输出9
lambda表达式可以使用async和await关键字来创建包含异步处理的lambda表达式和语句。这些lambda表达式被称为异步lambda,它们可以用来实现异步方法或任务。例如:
//使用async和await关键字创建异步lambda
Func> asyncLambda = async () =>
{
await Task.Delay(1000);
return42;
};
//调用异步lambda并获取结果int result = await asyncLambda();
Console.WriteLine(result); //输出42
使用lambda表达式作为委托或事件处理程序
委托是一种引用类型,它可以封装一个具有特定参数和返回值类型的方法。委托可以用来实现回调函数、事件处理程序、匿名方法等功能。lambda表达式可以直接表示为委托的代码,而不需要单独定义一个方法或一个委托类型。这样可以简化委托的创建和使用,提高代码的可读性和灵活性。
要使用lambda表达式作为委托,需要遵循以下几个步骤:
定义一个委托类型,或者使用系统预定义的泛型委托类型,如Action
创建一个lambda表达式,指定输入参数和表达式或语句块,并根据委托类型推断输入参数和返回值的类型。
将lambda表达式赋值给一个委托变量,或者直接作为参数传递给其他方法。
调用委托变量或方法,执行lambda表达式的主体。
例如,下面的代码演示了如何使用lambda表达式作为委托:
//定义一个委托类型delegateintCalculateHandler(int x, int y);
//创建一个lambda表达式,并赋值给一个委托变量
CalculateHandler sumHandler = (x, y) => x + y;
//调用委托变量,执行lambda表达式的主体
Console.WriteLine(sumHandler(1, 2)); //输出3//使用系统预定义的泛型委托类型
Func multiplyHandler = (x, y) => x * y;
//调用委托变量,执行lambda表达式的主体
Console.WriteLine(multiplyHandler(2, 3)); //输出6//直接将lambda表达式作为参数传递给其他方法
List numbers = new List() { 1, 2, 3, 4, 5 };
numbers.ForEach(n => Console.WriteLine(n * n)); //输出1 4 9 16 25
事件是一种特殊的委托,它可以在某个对象发生特定行为时通知其他对象。事件处理程序是一种特殊的方法,它可以在事件被触发时执行一些操作。lambda表达式可以直接表示为事件处理程序的代码,而不需要单独定义一个方法。这样可以简化事件处理程序的创建和使用,提高代码的可读性和灵活性。
要使用lambda表达式作为事件处理程序,需要遵循以下几个步骤:
定义一个事件,或者使用系统预定义的事件类型,如EventHandler
创建一个lambda表达式,指定输入参数和表达式或语句块,并根据事件类型推断输入参数和返回值的类型。
将lambda表达式添加到事件的订阅列表中,或者直接作为参数传递给其他方法。
触发事件,执行所有订阅了该事件的lambda表达式的主体。
例如,下面的代码演示了如何使用lambda表达式作为事件处理程序:
//定义一个按钮类classButton
{
//定义一个点击事件publicevent EventHandler Click;
//定义一个触发点击事件的方法publicvoidOnClick()
{
//如果有订阅了该事件的处理程序,则调用它们
Click?.Invoke(this, EventArgs.Empty);
}
}
//创建一个按钮对象
Button button = new Button();
//创建一个lambda表达式,并添加到点击事件的订阅列表中
button.Click += (sender, e) =>
{
Console.WriteLine("Button clicked");
};
//触发点击事件,执行lambda表达式的主体
button.OnClick(); //输出Button clicked
使用lambda表达式作为LINQ查询的谓词或选择器
LINQ是一种语言集成查询,它可以用来对各种数据源进行查询、筛选、排序、分组等操作。LINQ查询可以使用查询表达式或方法语法来编写,其中方法语法可以使用lambda表达式来指定查询的条件或投影。lambda表达式可以直接表示为谓词或选择器的代码,而不需要单独定义一个方法。这样可以简化LINQ查询的创建和使用,提高代码的可读性和灵活性。
要使用lambda表达式作为LINQ查询的谓词或选择器,需要遵循以下几个步骤:
定义一个数据源,或者使用系统预定义的数据源类型,如IEnumerable
创建一个lambda表达式,指定输入参数和表达式或语句块,并根据数据源类型推断输入参数和返回值的类型。
将lambda表达式作为参数传递给LINQ查询方法,如Where、Select、OrderBy等。
遍历或转换LINQ查询结果,执行lambda表达式的主体。
例如,下面的代码演示了如何使用lambda表达式作为LINQ查询的谓词或选择器:
//定义一个数据源
List numbers = new List() { 1, 2, 3, 4, 5 };
//创建一个lambda表达式,并作为参数传递给Where方法,筛选出偶数var evenNumbers = numbers.Where(n => n % 2 == 0);
//遍历LINQ查询结果,执行lambda表达式的主体foreach (var n in evenNumbers)
{
Console.WriteLine(n); //输出2 4
}
//创建一个lambda表达式,并作为参数传递给Select方法,将每个数乘以10var multipliedNumbers = numbers.Select(n => n * 10);
//遍历LINQ查询结果,执行lambda表达式的主体foreach (var n in multipliedNumbers)
{
Console.WriteLine(n); //输出10 20 30 40 50
}
//创建一个lambda表达式,并作为参数传递给OrderBy方法,按照数值大小排序var sortedNumbers = numbers.OrderBy(n => n);
//遍历LINQ查询结果,执行lambda表达式的主体foreach (var n in sortedNumbers)
{
Console.WriteLine(n); //输出1 2 3 4 5
}
使用lambda表达式作为Task.Run或Task.Factory.StartNew的参数
Task是一种表示异步操作的对象,它可以用来实现并行编程、异步编程、多线程编程等功能。Task可以使用Task.Run或Task.Factory.StartNew方法来创建和启动,这些方法可以接受一个委托作为参数,表示要在任务中执行的代码。lambda表达式可以直接表示为委托的代码,而不需要单独定义一个方法。这样可以简化Task的创建和使用,提高代码的可读性和灵活性。
要使用lambda表达式作为Task.Run或Task.Factory.StartNew的参数,需要遵循以下几个步骤:
创建一个lambda表达式,指定输入参数和表达式或语句块,并根据委托类型推断输入参数和返回值的类型。
将lambda表达式作为参数传递给Task.Run或Task.Factory.StartNew方法,创建并启动一个任务。
等待任务完成,获取任务的结果或异常。
例如,下面的代码演示了如何使用lambda表达式作为Task.Run或Task.Factory.StartNew的参数:
//创建一个lambda表达式,并作为参数传递给Task.Run方法,创建并启动一个任务var task = Task.Run(() =>
{ //在任务中执行一些耗时的操作
Thread.Sleep(1000);
//返回一个结果
return 42;
});
//等待任务完成,获取任务的结果
int result = task.Result;
Console.WriteLine(result); //输出42
//创建一个lambda表达式,并作为参数传递给Task.Factory.StartNew方法,创建并启动一个任务
var task2 = Task.Factory.StartNew(() =>
{
//在任务中执行一些耗时的操作
Thread.Sleep(1000);
//抛出一个异常
throw new Exception("Something went wrong");
});
//等待任务完成,获取任务的异常
try
{
task2.Wait();
}
catch (AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
{
Console.WriteLine(e.Message); //输出Something went wrong
}
}
使用lambda表达式作为表达式树
表达式树是一种表示代码结构的数据结构,它可以用来实现动态编译、元编程、LINQ提供程序等功能。表达式树可以使用Expression
要使用lambda表达式作为表达式树,需要遵循以下几个步骤:
创建一个lambda表达式,指定输入参数和表达式或语句块,并根据Expression
将lambda表达式作为参数传递给Expression
遍历或转换表达式树对象,获取表达式树的结构或编译为委托。
例如,下面的代码演示了如何使用lambda表达式作为表达式树:
//创建一个lambda表达式,并作为参数传递给Expression>类型的构造函数,创建一个表达式树对象
Expression> expression = (x, y) => x + y;
//遍历表达式树对象,获取表达式树的结构
Console.WriteLine(expression); //输出(x, y) => (x + y)
Console.WriteLine(expression.Body); //输出(x + y)
Console.WriteLine(expression.Parameters[0]); //输出x
Console.WriteLine(expression.Parameters[1]); //输出y//转换表达式树对象,编译为委托
Func func = expression.Compile();
//调用委托,执行lambda表达式的主体
Console.WriteLine(func(1, 2)); //输出3
使用lambda表达式作为异步方法
异步方法是一种使用async和await关键字来实现异步编程的方法,它可以用来实现非阻塞的UI、并发的网络请求、异步的IO操作等功能。异步方法可以使用Task或Task
要使用lambda表达式作为异步方法,需要遵循以下几个步骤:
创建一个lambda表达式,指定输入参数和表达式或语句块,并根据Task或Task
在lambda表达式中使用async和await
关键字来标记异步处理的代码,并使用await关键字来等待异步操作的完成。
- 将lambda表达式作为参数传递给Task或Task类型的方法,如Task.Run或Task.FromResult,创建并启动一个异步方法。
- 等待异步方法完成,获取异步方法的结果或异常。
例如,下面的代码演示了如何使用lambda表达式作为异步方法:
```c#//创建一个lambda表达式,并作为参数传递给Task.Run方法,创建并启动一个异步方法var task = Task.Run(async () =>
{
//在lambda表达式中使用async和await关键字来标记异步处理的代码await Task.Delay(1000); //等待1秒return42; //返回一个结果
});
//等待异步方法完成,获取异步方法的结果int result = await task;
Console.WriteLine(result); //输出42//创建一个lambda表达式,并作为参数传递给Task.FromResult方法,创建并启动一个异步方法var task2 = Task.FromResult(async () =>
{
//在lambda表达式中使用async和await关键字来标记异步处理的代码await Task.Delay(1000); //等待1秒thrownew Exception("Something went wrong"); //抛出一个异常
});
//等待异步方法完成,获取异步方法的异常try
{
await task2;
}
catch (Exception e)
{
Console.WriteLine(e.Message); //输出Something went wrong
}
以上是c# lambda表达式的5高频使用方法