C#Lambda表达式的理解应用
一、Lambda表达式的演变过程
Lambda表达式可以理解为是一个匿名函数,Lambda表达式可以包含表达式和语句,并且可以用于创建委托,以及C#编译器也能将它转换成表达式树。
对于Lambda表达式中都会使用这个运算符——“=>”,它读成“goes to”,该运算符的左边为输入参数,右边是表达式或者语句块。
using System;
namespace Lambda
{
class Program
{
//Lambda表达式使用演示
static void Main(string[] args)
{
//Lambda表达式的演变过程
//下面是C#1中创建委托实例的代码
Func<string,int> delegatetest1 = new Func<string,int>(Callbackmethod);
//C#2中用匿名方法来创建委托实例,此时就不需要额外定义回调方法Callbackmethod
Func<string,int> delegatetest2 = delegate(string text)
{
return text.Length;
};
//C#3中使用Lambda表达式来创建委托实例
Func<string,int> delegatetest3 = (string text) => text.Length;
可以省略参数类型string,把上面代码在简化为:
Func<string,int> delegatetest4 = text => text.Length;
//调用委托
Console.WriteLine("使用Lambda表达式返回字符串的长度为:“ + delegatetest("learning hard"));
}
}
}
二、Lambda表达式的使用
using System;
using System.Windows.Forms;
namespace Lambda表达式来记录事件Demo
{
class Program
{
static void Mian(string[] args)
{
//新建一个button实例
Button button1 = new Button() {Text = “点击我”};
//C# 2 中使用匿名方法来订阅事件
//button1.Click += delegate(object sender,EventArgs e)
//{
// ReportEvent("Click事件",sender,e);
//};
//button1.KeyPress += delegate(object sender,KeyPressEventArgs e)
//{
// ReportEvent("KeyPress事件,即键盘按下事件",sender,e);
//};
//C# 3Lambda表达式方式来订阅事件
//与上面使用匿名方法来订阅事件是不是简单了很多,并且也直观了
button1.Click += (sender,e) => ReportEvent("Click事件",sender,e);
button1.KeyPress += (sender,e) => ReportEvent("KeyPress事件,即键盘按下事件",sender,e);
//C# 3之前初始化对象时使用下面代码
//Form from = new Form();
//form.Name = "在控制台中创建的窗体";
//form.AutoSize = true;
//form.Controls.Add(button1);
//C# 3中使用对象初始化器
//与上面代码的比较中,也可以看出使用对象初始化之后代码简化了很多
Form form = new Form{Name = "在控制台中创建的窗体",AutoSize = true,Controls = {button1}};
//运行窗体
Application.Run(form);
}
//记录事件的回调方法
private static void ReportEvent(string title,object sender,EventArrgs e)
{
Console.WriteLine("发生的事件为:{0}", title);
Console.WriteLine("发生事件的对象为:{0}", sender);
Console.WriteLine("发生事件参数为: {0}", e.GetType());
Console.WriteLine();
Console.WriteLine();
}
}
}
三、表达式树
上面指出Lambda表达式除了可以用来创建委托外,C#编译器还可以将他们转换成表达式树—用于表示Lambda表达式逻辑的一种数据结构,表达式树也可以称作表达式目录树,它将代码表示成一个对象树,而不是可执行的代码。对于刚接触表达式树的可能有疑问—为什么需要把Lambda表达式转化为表达式目录树?对于表达式树的提出主要是为后面Linq to SQL做铺垫,一个Linq to SQL的查询语句并不是在C#的程序中执行的,而是C#编译器把它转化为SQL语句,把返回的结果在返回给一个IQueryable集合,所以Linq to SQL也采用了通常的ORM(Object - Relationship - Mapping)来设计的,相当于是一个ORM框架,不过这个框架只能与微软的SQL server数据库进行映射,对于其他类型的数据库却不可以,然而很多其他开发人员却对此进行了一些扩展,扩展了对其他数据库的支持。
下面先看看如何把Lambda表达式转化为表达式目录树:
using System;
using System.Linq.Expressions;
namespace表达式树Demo
{
class Program
{
//表达式树的演示
//static void Main(string[] args)
{
#region 将Lambda表达式转换为表达式树演示
//将Lambda表达式转换为Express的表达式树
//此时express不是可执行的代码,他现在是一个表达式树的数据结构
Console.WriteLine(“将Lambda表达式转化为表达式树的演示:”);
Expression<Func<int, int,int>> expression = (a,b) => a+b;
//获得表达式树的参数
Console.WriteLine("参数1:{0},参数2:{1}",expression.Parameters[0],expression.Parameters[1]);
//既然叫做树,那肯定有左右节点
//获取表达式树的主体部分
BinaryExpression body = (BinaryExpression) expression.Body;
//左节点,每个节点本身就是一个表达式对象
ParameterExpression left = (ParameterExpression)body.Left;
//右节点
ParameterExpression right = (ParameterExpression)body.Right;
Console.WriteLine("表达式主体为:");
Console.WriteLine(expression.Body);
Console.WriteLine("表达式树左节点为:{0}{4} 节点类型为:{1}{4}{4} 表达式右节点为:{2}{4} 节点类型为:{3}{4}", left.Name, left.NodeType, right.Name, right.NodeType,Environment.NewLine);
Console.Read();
#endregion
#region 把表达式树转化回可执行代码
// Compile方法生成Lambda表达式的委托
Console.WriteLine("按下Enter键进入将表达式树转换为Lambda表达式的委托演示:");
int result = expression.Compile()(2, 3);
Console.WriteLine("调用Lambda表达式委托结果为:" + result);
Console.ReadKey();
#endregion
}
}
}
补充:
1.匿名函数不等于匿名方法,匿名函数包含了匿名方法和Lambda表达式这两种概念。
2.Lambda作为表达式,可以被C#编译器转换为委托,也可以被编译器转换为表达式树,匿名方法只能转换为委托。
3.两者的共同点是都能被编译器转换为委托,Lambda表达式能完成几乎所有匿名方法能完成的事。