在说明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类包含两个属性:

  1. Type属性代表表达式求值后.NET类型,可把它视为一个返回类型。例如,一个表达式要获取一个字符串的长度,则该表达式的类型为int。
  2. 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)的更多相关文章

  1. C#中的Lambda表达式和表达式树

    在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...

  2. Lambda表达式和表达式树

    在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...

  3. C#复习笔记(4)--C#3:革新写代码的方式(Lambda表达式和表达式树)

    Lambda表达式和表达式树 先放一张委托转换的进化图 看一看到lambda简化了委托的使用. lambda可以隐式的转换成委托或者表达式树.转换成委托的话如下面的代码: Func<string ...

  4. 深入学习C#匿名函数、委托、Lambda表达式、表达式树类型——Expression tree types

    匿名函数 匿名函数(Anonymous Function)是表示“内联”方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取 ...

  5. lambda表达式和表达式树(深入理解c#)

    1.Lambda形式 1). Lambda表达式最冗长的形式: (显式类型的参数列表)=>{语句} 2). 大多数时候,都可以用一个表达式来表示主体,该表达式的值是Lambda的结果,在这些情况 ...

  6. C# 表达式树 创建、生成、使用、lambda转成表达式树~表达式树的知识详解

    笔者最近学了表达式树这一部分内容,为了加深理解,写文章巩固知识,如有错误,请评论指出~ 表达式树的概念 表达式树的创建有 Lambda法 和 组装法. 学习表达式树需要 委托.Lambda.Func& ...

  7. 无法将具有语句体的lambda表达式转换为表达式树

    很早就碰到了这个问题,当时也没有深入的研究,趁着空闲,遂把这个问题研究清楚. (一)普通案例 下面从一个普通的案例入手,下面准备两个List集合,都是放在内存里面的(需要模拟到远端执行的时候,我们是通 ...

  8. [.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门

    [.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门 本节导读: 认识表达式树(Expression Tree),学习使用Lambda创建表达式树,解析表达式树. 学习 ...

  9. [.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用

    [.net 面向对象程序设计进阶] (7) Lamda表达式(三) 表达式树高级应用 本节导读:讨论了表达式树的定义和解析之后,我们知道了表达式树就是并非可执行代码,而是将表达式对象化后的数据结构.是 ...

随机推荐

  1. android SQLiteOpenHelper使用示例

    我们大家都知道Android平台提供给我们一个数据库辅助类来创建或打开数据库,这个辅助类继承自SQLiteOpenHelper类,在该类的 构造器中,调用Context中的方法创建并打开一个指定名称的 ...

  2. nyoj 712 探 寻 宝 藏--最小费用最大流

    问题 D: 探 寻 宝 藏 时间限制: 1 Sec  内存限制: 128 MB 题目描述 传说HMH大沙漠中有一个M*N迷宫,里面藏有许多宝物.某天,Dr.Kong找到了迷宫的地图,他发现迷宫内处处有 ...

  3. UVA 11355 Cool Points(几何)

    Cool Points We have a circle of radius R and several line segments situated within the circumference ...

  4. Mac OS X 中vim开启配色和git补全

    问题起源:mac 下自带的git 无法补全命令,配色方案不完善 Mac OS Yosemite 10.10.3 git version 2.3.2 (Apple Git-55) 处理结果:git命令可 ...

  5. 【C#】3.算法温故而知新 - 快速排序

    快速排序相比冒泡排序,每次交换是跳跃式的.每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数放到基准点的右边.这样每次交换的时候就不会像冒泡排序一样只能在相邻 ...

  6. 每日一语:What is he getting at?

    What is he getting at? 他讲这话是什么意思? 2015-1-12

  7. Hill密码

    希尔密码(Hill Password)是运用基本矩阵论原理的替换密码,由Lester S. Hill在1929年发明.每个字母当作26进制数字:A=, B=, C=... 一串字母当成n维向量,跟一个 ...

  8. Android中Intent传值与Bundle传值的区别详解

    Android中Intent传值与Bundle传值的区别详解 举个例子我现在要从A界面跳转到B界面或者C界面   这样的话 我就需要写2个Intent如果你还要涉及的传值的话 你的Intent就要写两 ...

  9. Java中的IO流系统详解(转载)

    摘要: Java 流在处理上分为字符流和字节流.字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符.字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组. Java ...

  10. es2自动发现插件

    https://www.elastic.co/guide/en/elasticsearch/plugins/current/discovery-multicast-usage.html http:// ...