一、前言

一直想写一篇Dpper的定制化扩展的文章,但是里面会设计到对Lambda表达式的解析,而解析Lambda表达式,就必须要知道表达式树的相关知识点。我希望能通过对各个模块的知识点或者运用能够多一点的讲解,能够帮助到园友了解得更多。虽然讲解得不全面,如果能成为打开这块的一把钥匙,也是蜗牛比较欣慰的。

表达式系列目录

C# 表达式树讲解(一)

C# 表达式树遍历(二)

C# 表达式树分页扩展(三)

C# 表达式树Lambda扩展(四)

二、表达树理解

表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,它将我们原来可以直接由代码编写的逻辑以表达式的方式存储在树状的结构里,从而可以在运行时去解析这个树,然后执行,实现动态的编辑和执行代码。在.Net 里面的Linq to SQL就是对表达式树的解析。

这里先讲解下表达式和表达式树,表达式相信大家都知道,比如x+5或者5,都可以算是表达式,而表达式树里面的树指的二叉树,也就是表达式的集合,C#中的Expression类就是表达式类。对于一棵表达式树,其叶子节点都是参数或者常数,非叶子节点都是运算符或者控制符。

2.1、表达式的创建

Lambda表达式方法:

Expression<Func<int, int,bool>> fun = (x, y) => x < y

这种方法创建出的表达式根节点类型为ExpressionType.Lambda,Type类型为返回值类型typeof(bool)

组装法(通过 API 创建表达式树):

ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
Expression.Lambda<Func<int, bool>>(
numLessThanFive,
new ParameterExpression[] { numParam });

我们先创建了两个参数表达式num和5,然后用LessThan组装在一起,最终的表达式为“num<5”,expr的节点类型为LessThan,Type类型为typeof(bool)

我们先看看表达式树里面的构造

首先Expression<TDelegate>的功能是将强类型Lambda表达式表示为表达式树形式的数据结构,他的父类是LambdaExpression,比较他们代码可知,Lambda表达式的主体,名称和参数全部保存在LambdaExpression里面。

Expression<TDelegate>与LambdaExpression代码截图:

LambdaExpression里面的Body就是我们的表达式。

C#表达式给我们提供了丰富的表达式类,进入到LambdaExpression类里面

方法返回类型以“Expression”结尾的,基本上都是一个表达式类。

每个表达式代表的定义和创建方法,可以参照微软官方文档https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.binaryexpression?view=netframework-4.8

下面是平常使用最多的表达式

ConstantExpression:常量表达式

ParameterExpression:参数表达式

UnaryExpression:一元运算符表达式

BinaryExpression:二元运算符表达式

TypeBinaryExpression:is运算符表达式

ConditionalExpression:条件表达式

MemberExpression:访问字段或属性表达式

MethodCallExpression:调用成员函数表达式

Expression<TDelegate>:委托表达式

2.2、表达式的解析

表达式树解析

通过LambdaExpression类我们可以知道,表达式树包含:参数[Parameters],表达式树类型[NodeType],表达式[Body],返回类型[ReturnType],Lambda表达式的委托[Compile]以及Lambda表达式名称[name],如图所示:

表达式解析:

所有的表达式都包含:左节点【Left】,右节点【Right】,类型【NodeType】,不同的表达式还会有其他属性,这里的左右节点依旧是表达式。

下图是BinaryExpression表达式截图

表达式树和表达式里面的类型NodeType是一个枚举,一共有85个类型,有兴趣的朋友可以去了解下。

常用的类型如下:

ExpressionType.And:C#中类似于&

ExpressionType.AndAlso:C#中类似于&&

ExpressionType.Or:C#中类似于|

ExpressionType.OrElse:C#中类似于||

ExpressionType.Equal:C#中类似于==

ExpressionType.NotEqual:C#中类似于!=

ExpressionType.GreaterThan:C#中类似于>

ExpressionType.GreaterThanOrEqual:C#中类似于>=

ExpressionType.LessThan:C#中类似于<

ExpressionType.LessThanOrEqual:C#中类似于<=

ExpressionType.Add:C#中类似于+

ExpressionType.AddChecked:C#中类似于+

ExpressionType.Subtract:C#中类似于-

ExpressionType.SubtractChecked:C#中类似于-

ExpressionType.Divide:C#中类似于/

ExpressionType.Multiply:C#中类似于*

ExpressionType.MultiplyChecked:C#中类似于*

2.3、编译表达式树

在表达式创建那,我们组合创建了一个Lambda表达式,那么应该怎么使用它呢?在“表达式的解析”里面,LambdaExpression类和Expression<TDelegate>类都有一个Compile的方法,学名是Lambda表达式的委托,其实就是Lambda表达式编译函数的委托,所以我们只需要调用他,得到的结果就是一个函数方法。

代码修改如下:

ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
ConstantExpression five = Expression.Constant(5, typeof(int));
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expression<Func<int, bool>> lambda1 =
Expression.Lambda<Func<int, bool>>(
numLessThanFive,
new ParameterExpression[] { numParam }); Console.WriteLine($"Lambda的内容:{lambda1.ToString()}"); //表达式的编译
var func = lambda1.Compile();
Console.WriteLine($"Lambda的运行结果:{func(6)}");

运行结果

三、总结

这里我们对表达式做了基本的讲解,相信大家对Lambda表达式有了初步的了解,下面我们将继续讲解对一个表达式树的遍历。

C# 表达式树讲解(一)的更多相关文章

  1. C# 表达式树分页扩展(三)

    一.前言 前面我们知道了表达树的基本知识,也明白了怎么遍历和修改一个表达式,这里我们就一个实际的场景来进行功能开发. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) C# 表达式树 ...

  2. C# 表达式树遍历(二)

    一.前言 上一篇我们对表达式树有了初步的认识,这里我们将对表达式树进行遍历,只有弄清楚了他的运行原理,我们才可以对他进行定制化修改. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) ...

  3. C# 表达式树Lambda扩展(四)

    一.前言 本来计算这篇文章在后面需要运用的时候写的,但是既然写到表达式的扩展呢,就一起写完吧. 看到这个标题就有一种疑问,Lambda表达式本来就是表达式树,还需要怎么扩展?那就看看下面的内容,你就知 ...

  4. Linq系列(7)——表达式树之ExpressionVisitor

    大家好,由于今天项目升级,大家都在获最新代码,所以我又有时间在这里写点东西,跟大家分享. 在上一篇的文章中我介绍了一个dll,使大家在debug的时候可以可视化的看到ExpressionTree的Bo ...

  5. C# 委托、事件、表达式树理解

    1.什么是委托? 委托是一种动态调用方法的类型,属于引用型. 委托是对方法的抽象和封装.委托对象实质上代表了方法的引用(即内存地址) 所有的异步都是委托   委托就是函数当入参   委托被各种语法糖遮 ...

  6. 再讲IQueryable<T>,揭开表达式树的神秘面纱

    接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...

  7. [C#] C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  8. 轻量级表达式树解析框架Faller

    有话说 之前我写了3篇关于表达式树解析的文章 干货!表达式树解析"框架"(1) 干货!表达式树解析"框架"(2) 干货!表达式树解析"框架" ...

  9. 用五分钟重温委托,匿名方法,Lambda,泛型委托,表达式树

    这些对老一代的程序员都是老生常谈的东西,没什么新意,对新生代的程序员却充满着魅力.曾经新生代,好多都经过漫长的学习,理解,实践才能掌握委托,表达式树这些应用.今天我尝试用简单的方法叙述一下,让大家在五 ...

随机推荐

  1. JavaWeb配置详解(结合框架SpringMVC)

    详解 先说一说常识性的东西,我们的JavaWeb程序运行一开始走的是web.xml文件,这是我们的核心文件,可以说没有web.xml文件我们就无法运行项目,这个文件长什么样子,读者自己新建一个web项 ...

  2. Excel批量导入(导出同理)

    在做JavaWeb中添加数据使我们在所难免会遇到的,在大数据的环境下批量添加和批量删除是必须的,而批量删除只需要获取到我们需要删除的ID就可以了,在批量添加中我们就会遇到问题,问题是得到批量的数据,这 ...

  3. JVM 内存模型概述

    我们都知道,Java程序在执行前首先会被编译成字节码文件,然后再由Java虚拟机执行这些字节码文件从而使得Java程序得以执行.事实上,在程序执行过程中,内存的使用和管理一直是值得关注的问题.Java ...

  4. asp.net core 从单机到集群

    asp.net core 从单机到集群 Intro 这篇文章主要以我的活动室预约的项目作为示例,看一下一个 asp.net core 应用从单机应用到分布式应用需要做什么. 示例项目 活动室预约提供了 ...

  5. tensorflow学习笔记——图像数据处理

    喜欢摄影的盆友都知道图像的亮度,对比度等属性对图像的影响是非常大的,相同物体在不同亮度,对比度下差别非常大.然而在很多图像识别问题中,这些因素都不应该影响最后的结果.所以本文将学习如何对图像数据进行预 ...

  6. js中toFixed精度问题的解决办法

    toFixed() 方法可把 Number 四舍五入为指定小数位数的数字.例如将数据Num保留2位小数,则表示为:toFixed(Num):但是其四舍五入的规则与数学中的规则不同,使用的是银行家舍入规 ...

  7. Python 数据科学-Numpy

    NumPy Numpy :提供了一个在Python中做科学计算的基础库,重在数值计算,主要用于多维数组(矩阵)处理的库.用来存储和处理大型矩阵,比Python自身的嵌套列表结构要高效的多.本身是由C语 ...

  8. 利用递归,反射,注解等,手写Spring Ioc和Di 底层(分分钟喷倒面试官)了解一下

    再我们现在项目中Spring框架是目前各大公司必不可少的技术,而大家都知道去怎么使用Spring ,但是有很多人都不知道SpringIoc底层是如何工作的,而一个开发人员知道他的源码,底层工作原理,对 ...

  9. MUI-页面传参数

    点击第一个页面的标签,跳转到第二个页面,把第一个页面的值也传往目标页面 现在提供两种实现方式 注意:需要在手机运行才可以,用电脑浏览器可能不支持. 第一种方式  页面已创建,通过自定义事件传值 fir ...

  10. SpringIoC和SpringMVC的快速入门

    更多内容,欢迎关注微信公众号:全菜工程师小辉~ Spring的优势? 降低了组件之间的耦合性 ,实现了软件各层之间的解耦 可以使用容易提供的众多服务,如事务管理,消息服务等 容器提供单例模式支持 容器 ...