有看过我之前发表过的C#相关文章分享和阅读过我代码的朋友们可能会在我的代码里面经常看到各种各样的λ表达式动态拼接,C#的λ表达式树是一个好东西,也是别的语言学不来的,熟悉掌握λ表达式就能够实现各种linq场景的个性化操作,如动态拼接查询条件、排序方式等,也能够实现替代反射的高性能操作,比如我们常用到的IQueryable和IEnumerable,每个扩展方法就全是λ表达式树。

之前也分享过几篇关于λ表达式的文章,但鉴于还是有一部分初学者对于λ表达式树不太懂的,而网络上关于λ表达式树的科普不是很全面,今天就来填一下这个坑,分享一下λ表达式树的简单入门。

鉴于还有些伙伴不太清楚λ表达式树和委托的区别的,在教程正式开始之前,先科普下λ表达式树、lambda、委托它们之间的区别和联系吧。

λ表达式树、lambda、委托它们之间的区别和联系

1. 委托是一种类型,是方法的抽象,通过委托可以将方法以参数的形式传递给另一个方法,同时调用委托的时候,它缩包含的方法都会被实现。委托的关键字是delegate,可以自定义委托,也可以使用内置委托,通过简化,可以将Lambda表达式或Lambda语句赋值给委托,委托的调用包括同步调用和异步调用。

2. 表达式树(Expression)是一种数据结构,表达式树也称表达式目录树,是将代码以一种抽象的方式表示成一个对象树,树中每个节点本身都是一个表达式。表达式树不是可执行代码,它是一种数据结构。可以利用Lambda表达式进行声明,Lambda表达式的规则要符合Expression中Func委托的参数规则,但Lambda语句是不能声明的。

3. lambda是当委托只有一句话代码的时候的最简写形式。

4. Lambda表达式不仅可以用来创建委托实例,C#编译器也能够将他们转换成表达式树。

//Func委托,必须要有返回值,最后一个参数为返回值,前面为输入参数

λ表达式树入门

λ表达式树也是代码,我们把它当成另外一种动态语言学习就好了,它也有常量、参数、运算、判断等操作,λ表达式树最终的本质就是一个方法的编译状态,如:x=>x+1这个最基本的表达式,它对应的等效方法就是:

int 

我们分析x=>x+1表达式的每一个成分:

x:参数x;
=>:{}花括号;
+:add操作;
1:常量;

那为什么叫表达式树呢?

x=>x+1它的每一个成分都是一个节点,每个节点之间进行关联,得到最终的表达式,故称之为表达式树。如图所示:

再比如:(a,b)=>a*3+b*4,可视化结构如下:

通过Expression类构造一个最基本的λ表达式树

简单介绍之后,我们就开始实战吧,我们从最简单的开始,构造上面两个基本例子:

x=>x+1

var 

一个最基本的表达式树编译完成,我们输出看一下长什么样子吧,并调用func(10)看看得到什么结果:

(a,b)=>a*3+b*4

看上去比上面的例子复杂了一点,但我们把它拆分成两个基本的表达式处理就好了,按照上面的图例,我们从下往上进行构建:

先组合a*3,再组合b*4,最后再将a*3和b*4进行两两组合即可完成。

var 

我们再来构造一个更复杂的表达式:

(a,b,c,d,e)=>((a+b)*(c-d))%e

有点蒙了吧,我们还是拆成最基本的两两组合就好了:

var 

感觉这玩意儿有点意思了吧!接下来继续深入研究一些基本操作。

测试类

为方便接下来的示范,我们先新建一个class:

public 

替代反射

创建实例new MyClass(100)

Expression.New操作可为class创建实例对象,比如我想通过λ表达式树实现var myClass = new MyClass(100); 其可视化结构如下:

代码实现:

var newExpression = Expression.New(typeof(MyClass).GetConstructor(new[] { typeof(int) }), Expression.Constant(100)); // 有参构造函数方式
//var newExpression = Expression.New(typeof(MyClass)); //无参构造函数方式
var lambda = Expression.Lambda<Func<MyClass>>(newExpression);
var myClass = lambda.Compile()();

获取属性值e=>e.MyProperty

操作对象的属性我们需要用到Expression.Property,e=>e.MyProperty表达式分析得到两部分:参数和属性,也是一种基本表达式

Expression.Parameter可得到参数e;Expression.Property可得到属性MyProperty:

var 

为属性赋值e=>e.List=new List<string>(){"sdf"}

结合上面的属性操作,既然能获取属性,那就一定能设置属性值,Expression.Assign操作便是赋值操作

var 

调用方法e=>e.GetHashCode();

调用方法通过Expression.Call进行对象的方法调用,调用前需要先获取被调用的方法对象

var 

调用有参方法e=>e.SayHello("你好")

var 

调用Linq扩展方法e=>e.List.Contains("s")

首先我们要先获取到IEnumerable的Contains泛型扩展方法:

typeof

其次扩展方法的调用需要通过一个null实例进行调用

Expression

对于这样的链式调用,那λ表达式树的数据结构是什么样的呢?这种我们考虑从前往后构建就好了,翻译成树状结构如下:

所以完整代码如下:

var 

以上对对象的基本操作完了,我们再来一点复杂的,调用Linq扩展方法

e=>e.List.Any(item=>item.Contains("s"))

这看上去有点懵,表达式嵌套表达式,我们结合之前的方法调用和扩展方法调用,打一套组合拳就好了,表达式它也是一种参数类型嘛,我们先从里往外,再从前往后,λ表达式树的数据结构如下,先上图再写代码就不再懵:

所以,代码如下:

var 

对象的玩法暂时就只想到了这么多,以后想到了别的案例再随时补充。

三目表达式x=>x>60?"及格":"不及格"

这个表达式需要用到Expression.Condition,即可生成三目表达式的λ表达式树。其数据结构如下图:

代码实现如下:

var 

很简单是吧,那就又来个组合拳吧。

e => e.MyBool ? "真的" : "假的";

三目运算符+成员访问,还好,不算有难度。

var 

null值表达式e=>e.MyProperty??"s"

Expression.Coalesce便是对标的C#6专属的null值表达式

var 

类型转换Convert.ToInt32(x)

Expression.Convert即等价于Convert静态类,如通过Expression.Convert替代Convert.ToInt32:

var 

声明一个数组对象

Expression.NewArrayBounds即可生成一个创建数组对象的表达式:

var 

现在有了这么多的基础储备,那么接下来就来点复杂的实战吧!

实现条件表达式m=>m.MyProperty.Contains("ldqk")||m.List.Any(s=>s.Length>1&&s.Contains("a"))

我们还是先画出流程图,写代码不乱

写代码也没有必要按照刚才说的从内到外从前往后的顺序,也可以按局部到全部的方式来。我们一步一步便得到下面的代码:

var 

链式调用s=>s.List.Select(e => e.Length).OrderBy(x=>x).FirstOrDefault() > 1

这就比上面的这个例子简单多了,直接从左往右一步一步实现就好了

var 

λ表达式树的高级用法

由于知乎的篇幅限制,这一节内容请参考这个链接:

C#的λ表达式树(LambdaExpression)保姆级超详细简单入门教程_懒得勤快的博客_互联网分享精神​masuit.com

总结

其实λ表达式树并不难,看上去很高深的东西,只有理解了其中的原理,还是很快可以上手的!毕竟在实际项目中还是很广泛应用的,掌握λ表达式树打一套组合拳,就能够实现各种各样的应用,甚至动态编译!

λ表达式树的实际应用案例

给EF Core增加AddOrUpdate方法:

通过Expression表达式树,为EF Core找回AddOrUpdate方法​masuit.com

给linq增加And和Or扩展:

https://github.com/ldqk/Masuit.Tools/blob/master/Masuit.Tools/Linq/LinqExtension.cs​github.com

通过λ表达式树自己实现一个AutoMapper:

https://github.com/ldqk/Masuit.Tools/blob/master/Masuit.Tools/Mapping/ExpressionMapper.cs​github.com

通过λ表达式树实现对象的深克隆:

https://github.com/ldqk/Masuit.Tools/blob/master/Masuit.Tools/Mapping/ExpressionCpoier.cs​github.com

将字符串转换成λ表达式的项目:

https://github.com/zzzprojects/Eval-Expression.NET​github.com

将字符串转换成动态Linq:

https://github.com/zzzprojects/System.Linq.Dynamic​github.com

动态组合条件表达式:

dbelmont/ExpressionBuilder​github.com

还有很多很多这样的项目和应用,这里就不再一一列举了,LinqToAnything!λ表达式树是linq的基石,linq是万能的!

最后,给大家留几个思考题吧

1. Expression.Lambda(Expression.Parameter(typeof(int), "x"), Expression.Parameter(typeof(int), "x"))这种写法有没有问题?为什么?

2. 使用λ表达式树如何自己实现一个字符串算式的计算,如输入:"5x3+4",输出15?

转自原文链接:

C#的λ表达式树(LambdaExpression)保姆级超详细简单入门教程_懒得勤快的博客_互联网分享精神​masuit.com

什么是m叉树_C#的λ表达式树(LambdaExpression)保姆级超详细简单入门教程相关推荐

  1. 树链剖分(超详细!!!)

    一.轻重边剖分的过程 使用两次dfs来实现.剖分过程中要计算如下7个值: father[x]:x在树中的父亲 size[x]:x的子树结点数(子树大小) dep[x]:x在树中的深度 son[x]:x ...

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

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

  3. lambda表达式树

    一.定义: 表达式树又称为表达式目录树,以数据形式表示语言级代码.所有的数据都存储在树结构中,每个结点表示一个表达式(Expression). 二.要点: –Lambda表达式的参数类型可以忽略,因为 ...

  4. 表达式树 java_Linq表达式树编译非平凡的对象常量,并以某种方式引用它们

    通常,在编译表达式树时,我会想到不是基元类型或字符串的常量是不可能的 . 但是,这段代码: public class A { public int mint = -1; } public static ...

  5. c语言后缀表达式构造二叉树,C ++程序为后缀表达式构造表达式树

    表达式树基本上是用于表示表达式的二叉树.在表达式树中,节点对应于运算符,每个叶节点对应于操作数.这是一个C ++程序,用于按顺序,前顺序和后顺序遍历为后缀表达式构造一个表达式树. 算法Begin Fu ...

  6. 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截...

    程序猿修仙之路--数据结构之你是否真的懂数组? 数据结构 但凡IT江湖侠士,算法与数据结构为必修之课.早有前辈已经明确指出:程序=算法+数据结构  .要想在之后的江湖历练中通关,数据结构必不可少.数据 ...

  7. Lambda表达式和表达式树

    一: Lambda表达式 首先,表达式的类型本身并非委托类型,但它可以通过多种方式隐式或者显式地转换成一个委托实例.匿名函数这个术语同时涵盖了匿名方法和Lambda,很多情况下两者可以使用相互转换原则 ...

  8. 表达式树 php,Linux_LINQ学习笔记:表达式树,构建查询表达式 本节中, 我们 - phpStudy...

    构建查询表达式 本节中, 我们假设我们拥有一个这样的实体类: 1: [Table] public partial class Product 2: 3: { 4: 5: [Column(IsPrima ...

  9. 表达式树amp;amp;无根树转化为有根树

    //将无根树转化为有根树 vector<int>g[maxn]; void read-tree() { int u,v; scanf("%d",&n); for ...

  10. 干货!表达式树解析框架(3)

    最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html 这应该是年前最后一篇了,接下来的时间就要陪陪老婆孩子了 关于表达 ...

最新文章

  1. P4915 帕秋莉的魔导书
  2. 我如何使用React和Typescript在freeCodeCamp中构建天气应用
  3. c 最大子序列和_最大连续子序列
  4. ae插件Particle Projection for Mac(AE粒子投影插件)
  5. mysql系统特性_MySQL · 引擎特性 · InnoDB 事务系统
  6. spring+hibernate:在applicationCOntext.XML中配置C3P0参数说明
  7. 旋钮编码器c代码_电机编码器故障检修,其实跟编码器没有关系
  8. 小米笔记本pro充电测试软件,小米笔记本 Pro 评测:高端已成,性价比不变
  9. 阿里Sophix 集成
  10. 使用Excel制作证件照之替换背景色
  11. 中文ISBN公开信息查询接口
  12. VMware虚拟文件(.vmdk)瘦身(宿主为Windows)
  13. Effective Java 经典学习(一)
  14. 基于AM5728 DSP JTAG连接调试方法
  15. MySQL查询优化方法
  16. JavaScript葵花宝典(基础)
  17. 抓包工具 - Wireshark(详细介绍与TCP三次握手数据分析)
  18. JAVA 把base64图片数据转为本地图片
  19. CSU - 2135 Appositive Body
  20. 财务分析与决策:同型分析【转】

热门文章

  1. 后台管理怎样用html实现,后台管理实现
  2. 百炼JAVA-----实现家庭收支记账软件
  3. html5 app 原理,浅析开发html5 app的三大优势
  4. 解决:本地计算机无法复制文件到远程计算机
  5. OTA,一个万亿市场的风口
  6. 基于深度学习的自然场景文字识别系统研究 faster-RCNN + CRNN (一)
  7. 【ArcGIS风暴】气象台站气温(降水)矢量数据插值成栅格气温(降水)空间数据
  8. ThreadPoolExecutor线程池终止
  9. 13号线ab线规划图_北京地铁13号线拆分成这样了(附图)
  10. 微信小程序 内容评论-回复评论-回复回复的实现