16.C#初见Lambda表达式及表达式树(九章9.1-9.3)
在说明Lambda相关知识前,我们需要了解Lambda表达式常用于LINQ,那么我们来聊下LINQ。
LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态。这些操作表示了各种关于数据的逻辑:如何过滤、如何排序以及如何将不同的数据源连接在一起,等等。执行委托只是LINQ的众多能力之一。为了富有效率地使用数据库和其他查询引擎,我们需要以一种不同的方式来表示管道中的各个操作。这种不同的方式就可以使用Lambda表达式来表现。下面分别使用委托(使用匿名函数)和Lambda表达式来作出同样的事情:返回一个人的到现在一共活了多少天。
class Person
{
public DateTime BirthDay { get; set; }
} public delegate int GetLifeDays(Person p);//声明一个委托类型
static void Main(string[] args)
{
Person p = new Person() { BirthDay = new DateTime(, , ) }; GetLifeDays gfd = delegate (Person x) { //实例化一个委托
return (DateTime.Now - x.BirthDay).Days;
};
Console.WriteLine(gfd(p)); GetLifeDays gfd1 = (Person x) => { return (DateTime.Now - x.BirthDay).Days; };
Console.WriteLine(gfd1(p)); GetLifeDays gfd2 = (Person x) => (DateTime.Now - x.BirthDay).Days; //去除了后面的大括号,“;”为表达式结束,不是Lambda的结束
Console.WriteLine(gfd2(p)); GetLifeDays gfd3 = (x) => { return (DateTime.Now - x.BirthDay).Days; }; //让编译器推断参数的类型
Console.WriteLine(gfd3(p)); GetLifeDays gfd4 = (x) => (DateTime.Now - x.BirthDay).Days; //同时省去参数类型和大括号
Console.WriteLine(gfd4(p)); GetLifeDays gfd5 = x => (DateTime.Now - x.BirthDay).Days; //再进一步,省去参数列表的括号
Console.WriteLine(gfd5(p)); Console.ReadKey();
}
上述是单一参数的各种情况,对于有两个或多个参数的,效果是"一个到到从出生到某一天的相隔天数",某一天肯定是要大于出生那天啦。
public delegate int GetDaysTo(Person p, DateTime d);
static void Main(string[] args)
{
Person p = new Person() { BirthDay = new DateTime(, , ) }; DateTime d = new DateTime(, , );
//使用匿名方法
GetDaysTo gdt = delegate (Person x, DateTime y)
{
return (y - x.BirthDay).Days;
};
Console.WriteLine(gdt(p, d)); GetDaysTo gdt1 = (Person x, DateTime y) => { return (y - x.BirthDay).Days; };
Console.WriteLine(gdt1(p, d)); GetDaysTo gdt2 = (Person x, DateTime y) => (y - x.BirthDay).Days;
Console.WriteLine(gdt2(p, d)); GetDaysTo gdt3 = (x, y) => (y - x.BirthDay).Days;
Console.WriteLine(gdt3(p, d)); //GetDaysTo gdt4 = x, y => (y - x.BirthDay).Days; Error
//Console.WriteLine(gdt4(p, d)); Console.ReadKey();
}
可以看出当参数为两个或两个以上时,不能省略参数列表中的括号,那也可以想像在语句两条或两条以上时,不能省略大括号。
下面结合之前的知识,对一个列表使用ambda表达式进行操作。
//使用集合初始化器
List<Person> l = new List<Person> {
new Person { BirthDay=new DateTime(,,)},
new Person { BirthDay=new DateTime(,,)},
new Person { BirthDay=new DateTime(,,)},
new Person { BirthDay=new DateTime(,,)},
new Person() { BirthDay=new DateTime(,,)}
}; //找到大于new DateTime(1890,1,1)的人
var result0 = l.FindAll(x => x.BirthDay > new DateTime(, , )); //按年龄从小到大排序
l.Sort((x, y) => x.BirthDay > y.BirthDay ? - : );
foreach (var e in l)
{
Console.WriteLine((DateTime.Now - e.BirthDay).Days);
} //循环打印每个人的出生天数,效果和上面的foreach一样
l.ForEach(x => Console.WriteLine((DateTime.Now - x.BirthDay).Days)); //找到BirthDay=new DateTime(1890,12,12)的人
var result1 = l.Find(x => x.BirthDay == new DateTime(, , ));
接下来,我们来说下表达式树,.NET3.5的表达式提供了一种抽象的方式将一些代码表示成一个对象树,表达式树主要用于LINQ。System.Linq.Expressions命名空间包含了代表表达式的各个类,它们都继承于Expression,一个抽象的主要包含一些静态工厂方法的类,这些方法用于创建其它表达类的实例。
Expression类包含两个属性:
- Type属性代表表达式求值后.NET类型,可把它视为一个返回类型。例如,一个表达式要获取一个字符串的长度,则该表达式的类型为int。
- NodeType属性返回所代表的表达式的种类。它是ExpressionType枚举的成员。
Expression first = Expression.Constant();
Expression result = Expression.Add(first, first);
Console.WriteLine(result);
断点对象各属性


上图分别为first对象和result对象的各属性值。
- 将表达式树编译成委托
LambdaExpression是从Expression派生的类型之一。泛型类Expression<TDelegate>又是从LambdaExpression中派生。Expression和Expression<TDelegate>区别在于泛型类以静态类的方法标识了它是什么各类的表达式,也就是说,它确定了返回类型和参数。很显然,这是用TDelegate类型参数来表示的,它必须是一个委托类型。LambdaExpression有一个Compile方法能创建恰当类型的委托。Expression<TDelegate>也有一个同名的方法 ,但它静态类型化返回TDelegate类型的委托。如:
Expression first = Expression.Constant();
Expression result = Expression.Add(first, first);
Func<int> add = Expression.Lambda<Func<int>>(result).Compile();
Console.WriteLine(add()); //
- 将C#Lambda表达式转换为表达式树
Lambda表达式能显式或隐式地转换为恰当的委托实例,然而这些并非唯一能进行的转换,还可以要求编译器通过你的Lambda表达式构建一个表达式树,在执行时创建Expression<TDelegate>的一个实例。如
Expression<Func<int>> re = () => ;
Func<int> add0 = re.Compile();
Console.WriteLine(add0());
后面的那些内容真心太复杂了,自己实在理解不了,而且日常使用中也没有使用过,没有底气聊这个话题,想深入的朋友可以自己深入去了解,这里就做罢了吧。
请斧正。
16.C#初见Lambda表达式及表达式树(九章9.1-9.3)的更多相关文章
- C#中的Lambda表达式和表达式树
在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...
- Lambda表达式和表达式树
在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...
- C#复习笔记(4)--C#3:革新写代码的方式(Lambda表达式和表达式树)
Lambda表达式和表达式树 先放一张委托转换的进化图 看一看到lambda简化了委托的使用. lambda可以隐式的转换成委托或者表达式树.转换成委托的话如下面的代码: Func<string ...
- 深入学习C#匿名函数、委托、Lambda表达式、表达式树类型——Expression tree types
匿名函数 匿名函数(Anonymous Function)是表示“内联”方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取 ...
- lambda表达式和表达式树(深入理解c#)
1.Lambda形式 1). Lambda表达式最冗长的形式: (显式类型的参数列表)=>{语句} 2). 大多数时候,都可以用一个表达式来表示主体,该表达式的值是Lambda的结果,在这些情况 ...
- C# 表达式树 创建、生成、使用、lambda转成表达式树~表达式树的知识详解
笔者最近学了表达式树这一部分内容,为了加深理解,写文章巩固知识,如有错误,请评论指出~ 表达式树的概念 表达式树的创建有 Lambda法 和 组装法. 学习表达式树需要 委托.Lambda.Func& ...
- 无法将具有语句体的lambda表达式转换为表达式树
很早就碰到了这个问题,当时也没有深入的研究,趁着空闲,遂把这个问题研究清楚. (一)普通案例 下面从一个普通的案例入手,下面准备两个List集合,都是放在内存里面的(需要模拟到远端执行的时候,我们是通 ...
- [.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门
[.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门 本节导读: 认识表达式树(Expression Tree),学习使用Lambda创建表达式树,解析表达式树. 学习 ...
- [.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用
[.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用 本节导读:讨论了表达式树的定义和解析之后,我们知道了表达式树就是并非可执行代码,而是将表达式对象化后的数据结构.是 ...
随机推荐
- poj 3177 Redundant Paths
题目链接:http://poj.org/problem?id=3177 边双连通问题,与点双连通还是有区别的!!! 题意是给你一个图(本来是连通的),问你需要加多少边,使任意两点间,都有两条边不重复的 ...
- XNote Ver:0.79
隐藏主窗后,双击小图标显示主窗. 支持拖拉网页文字到小图标上,直接在当前项目上创建下级资料项目. 项目分类限50个汉字.
- DAC使用基本准则
DAC Nyquist Zones, Zero Order Hold, and Images why do the Fout images exist in every Nyquist zone? W ...
- 【C#】3.算法温故而知新 - 快速排序
快速排序相比冒泡排序,每次交换是跳跃式的.每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数放到基准点的右边.这样每次交换的时候就不会像冒泡排序一样只能在相邻 ...
- android应用中去掉标题栏的方法
现在我坚定的认为写技术博客对自己有很大的帮助,写博客给自己一个学而思的机会. 在Android中去掉标题栏有三种方法,它们也有各自的特点. 1.在代码里实现 this.requestWindowFea ...
- 注解与反射 ---Spring与Mybatis等框架的实现原理
Java中各大框架,无论是AOP 还是 IoC 其基本实现思路都是源自Java 运行时支撑的反射功能, 而反射最基本的一点就是 任何一个类 其在JVM环境中,都有一个对象的Class对象,这个对象提供 ...
- 6月27日 OGDF不同的布局算法
检查不同布局算法 备注 CircularLayout 可以非连通 FastMultipoleMultilevelEmbedder FMMMLayout 可以非连通 StressMajoriz ...
- 正则基础之——环视(Lookaround)
环视基础 环视只进行子表达式的匹配,不占有字符,匹配到的内容不保存到最终的匹配结果,是零宽度的.环视匹配的最终结果就是一个位置. 环视的作用相当于对所在位置加了一个附加条件,只有满足这个条件,环视子表 ...
- AFN框架基本使用
0.AFN框架基本使用 0.1 AFN内部结构 AFN结构体 - NSURLConnection + AFURLConnectionOperation(已经被废弃) + AFHTTPRequestOp ...
- 或得的一个div是变量时