Lambda 表达式是 C# 3.0 中最重要的特性之一,另外一个同样重要的特性是 Linq
Lambda 表达式简介
Lambda 表达式可以理解为一个匿名方法,它可以包含表达式和语句,并且勇于创建委托或转换表达式树。在使用 Lambda 表达式时,都会使用 => 运算符(读作“goes to”),该运算符的左边是匿名方法的输入参数,右边则是表达式或语句块
Lambda 表达式的演变过程
大家都可以认为匿名方法是 Lambda 表达式的前世,下面代码掩饰了 Lambda 表达式从匿名方法一路演变而来的过程
代码语言:javascript复制class Program
{
static void Main(string[] args)
{
// C# 1.0 中创建委托实例的代码
Func<string, int> delegateTest1 = new Func<string, int>(CallbackMethod);
// C# 2.0 中用匿名方法来创建委托实例,此时不需要额外定义回调方法了
Func<string, int> delegateTest2 = delegate(string text)
{
return text.length;
};
// C# 3.0 中使用 Lambda 表达式来创建委托实例
Func<string, int> delegateTest3 = (string text) => text.length;
// 此时也可以省略圆括号
Func<string, int> delegateTest = text => text.length;
}
}
虽然有了匿名方法,但是开发人员对此并不买账,很多人觉得用起来很麻烦,所以 C# 3.0 中又提出了 Lambda 表达式,替代匿名方法。尽管 Lambda 表达式完全颠覆了之前的编码风格,但是由于够简洁,一旦习惯上,就会喜欢上它
Lambda 表达式的使用
在实际开发过程中,委托的用途莫过于订阅事件了。为加深大家对 Lambda 表达式的理解,这里选择演示用 Lambda 表达式去订阅事件
首先给出的是 C# 3.0 之前的订阅代码,形成对比。具体的演示代码如下:
代码语言:javascript复制using System;
Using System.Windows.Forms;
class Program
{
static void Main(string[] args)
{
Button button1 = new Button();
button1.Text = "点击我";
// C# 2.0 中使用匿名方法来订阅事件
button1.Click = delegate(object sender, EventArgs e)
{
ReportEvent("Click事件", sender, e);
};
button1.KeyPress = delegate(object sender, keyPressEventArgs e)
{
ReportEvent("KeyPress事件", sender, e);
};
// C# 3.0 前,初始化对象时会使用以下代码
Form form = new Form();
form.Name = "test";
form.AutoSize = true;
form.Controls.Add(button1);
Application.Run(form);
}
private static void ReportEvent(string title, object sender, EventArgs e)
{
Console.WriteLine("发生的事件为:{0}", title);
}
}
我们再来用 C# 3.0 的特性实现同样的效果:
代码语言:javascript复制using System;
Using System.Windows.Forms;
class Program
{
static void Main(string[] args)
{
Button button1 = new Button();
button1.Text = "点击我";
// C# 3.0 中使用 Lambda 表达式方式来订阅事件
button1.Click = (object sender, EventArgs e) => ReportEvent("Click事件", sender, e);
button1.KeyPress = (object sender, keyPressEventArgs e) => ReportEvent("KeyPress事件", sender, e);
// C# 3.0 中使用对象初始化器
Form form = new Form() { Name = "test", AutoSize = true, Controls = { button1 } };
Application.Run(form);
}
private static void ReportEvent(string title, object sender, EventArgs e)
{
Console.WriteLine("发生的事件为:{0}", title);
}
}
从以上代码可以看出,使用 C# 3.0 的对象初始化器和 Lambda 表达式,代码确实简洁了不少
表达式也有树结构——表达式树
Lambda 表达式除了可以用来创建委托,还可以转换为表达式树。表达式树是用来表达 Lambda 表达式逻辑的一种数据结构,它将代码表示成一个对象树,而非可执行的代码。你可以将表达式树理解为一种 数据结构,即类似数据结构的栈和队列,只不过表达式树泳鱼表示 Lambda 表达式的逻辑罢了
那么为什么要提出表达式目录树呢?主要是为了后面的 Linq to SQL作铺垫
动态地构造一个表达式树
代码语言:javascript复制using System;
using System.Linq.Expressions;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
// 表达式参数
ParameterExpression a = Expression.Parameter(typeof(int), "a");
ParameterExpression b = Expression.Parameter(typeof(int), "b");
// 表达式主体部分
BinaryExpression binary = Expression.Add(a, b);
// 构建表达式树
Expression<Func<int, int, int>> expression = Expression.Lambda<Func<int, int, int>>(binary, a, b);
// 分析树结构,获取表达式树的主体部分
BinaryExpression body = (BinaryExpression)expression.Body;
// 左节点
ParameterExpression left = (ParameterExpression)body.Left;
// 右节点
ParameterExpression right = (ParameterExpression)body.Right;
}
}
}
上面代码演示了通过一个表达式动态地构造表达式树对象,然后输出表达式树的结构、主体和左右节点的过程
通过 Lambda 表达式来构造表达式树
前面代码演示了动态地构造表达式树的方法,除此之外,你还可以直接使用 Lambda 表达式来构造表达式树,具体构造过程如下:
代码语言:javascript复制using System;
using System.Linq.Expressions;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
// 构建表达式树
Expression<Func<int, int, int>> expression = (a, b) => a b;
// 分析树结构,获取表达式树的主体部分
BinaryExpression body = (BinaryExpression)expression.Body;
// 左节点
ParameterExpression left = (ParameterExpression)body.Left;
// 右节点
ParameterExpression right = (ParameterExpression)body.Right;
}
}
}
从以上代码可以看出,通过 Lambda 表达式来构造表达式树的过程非常简单,只需要把 Lambda 表达式树赋给一个表达式树变量即可
如何把表达式树转换成可执行代码
看完前面的代码,你肯定问:“表达式树是一种树形数据结构,但最终还是需要得到代码的执行结果,有没有一种发过誓把表达式树转换成可执行代码,然后输出执行成果呢?”
代码语言:javascript复制using System;
using System.Linq.Expressions;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
// 构建表达式树
Expression<Func<int, int, int>> expression = (a, b) => a b;
Func<int, int, int> delInstance = expression.Compile();
int result = delInstance(2, 3);
Console.WriteLine(result); // 5
}
}
}
以上代码通过Expression类的Compile方法将表达式树编译成委托实例,然后通过委托调用的方式得到了两个数的和
归纳总结
Lambda 表达式是 C# 3.0 最重要的特性之一,我们应该掌握它,以更好地学习和使用 Linq