[C# Expression] 之基础概念
00 | 什么是表达式树
表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的二元运算等。可以对表达式树中的代码进行编辑和运算。 这样能够动态修改可执行代码、在不同数据库中执行 LINQ 查询以及创建动态查询。 表达式树还能用于动态语言运行时 (DLR) 以提供动态语言和 .NET 之间的互操作性,同时保证编译器编写员能够发射表达式树而非 Microsoft 中间语言 (MSIL)。 这段话是来自官网( [表达式树 (C#) | Microsoft Docs](表达式树 (C#) | Microsoft Docs) )的定义。
在 C# 中,我们可以通过 Expression 的方式来手动创建表达式树,比如:
[HttpGet]
public IActionResult Expression()
{
// 查询 年龄Age 大于 18 的元素
Expression<Func<User,bool>> expression1 = x => x.Age > 18;
return Ok();
}
那么,x.Age > 18 这一表达式,它的树状结构是这样的:

通过 Visual Studio 自带的查看变量或添加监视的方式,我们可以发现其中 树的根节点(NodeType)是 GreaterThan,左节点(Left)是 x.Age,右节点(Right)是 18。所以由此就可以大概画出树状结构。

最后,通过这种树状结构,C# 就可以帮我们将表达式编译成具体的 SQL 执行语句。
如果想更清晰的查看表达式树的结构,可以 nuget 一个包( ExpressionTreeToString ),将表达式结构转换成字符串
PM> Install-Package ZSpitz.Util -Version 0.1.116
Expression<Func<User, bool>> expression = u => u.Age >= 18;
var treeStr = expression.ToString("Object notation", "C#");
// 输出为下面字符串
var u = new ParameterExpression {
Type = typeof(User),
IsByRef = false,
Name = "u"
};
new Expression<Func<User, bool>> {
NodeType = ExpressionType.Lambda,
Type = typeof(Func<User, bool>),
Parameters = new ReadOnlyCollection<ParameterExpression> {
u
},
Body = new BinaryExpression {
NodeType = ExpressionType.GreaterThanOrEqual,
Type = typeof(bool),
Left = new MemberExpression {
Type = typeof(int),
Expression = u,
Member = typeof(User).GetProperty("Age")
},
Right = new ConstantExpression {
Type = typeof(int),
Value = 18
}
},
ReturnType = typeof(bool)
}
01 | Expression 和 Func 的区别
- Expression 存储了运算逻辑,可以将其保存成抽象语法树(AST),可以在运行时动态获取运算逻辑。
- Func 只是存储了结果,无法保存成语法树,也无法动态获取运算逻辑。
所以,在 EFCore 中,使用表达式对数据库数据进行查询中,我们应该选择 Expression 而不是 Func,因为使用了 Func ,实际上并无法将 Func 中的表达式转换成 SQL,而是在将所有数据加载到内存后,在内存中在过滤 Func 中的条件。
简单来说就是,此时要筛选 User 表中年龄大于18的数据,可以有这两种写法
// 这种写法,实际生成的 SQL 语句, 大概是这样的 SELECT * FROM User as T WHERE T.age > 18
Expression<Func<User,bool>> expression1 = x => x.Age > 18;
dbContext.User.Where(expression1).toList();
// 而这种, 生成的语句是这样的 SELECT * FROM User, 然后将 User 表中所有数据加载到内存中后, 在进行 age > 18 的过滤
Func<User, bool> func1 = x => x.Age > 18;
dbContext.User.Where(func1).toList();
02 | 通过代码创建表达式树
- ParameterExpression
- BinaryExpression
- MethodCallExpression
- ConstantExpression
这些类几乎都没有提供构造方法,而且所有的属性都几乎只是只读。因此我们一般不会直接创建这些类的实例,而是调用 Expression 类的 Parameter、MakeBinary、Call、Constant等静态方法来生成,这些静态方法我们一般称作创建表达式树的工厂方法,而属性则通过方法参数类设置。
动态将表达式:u => u.Age >= 18; 通过代码构建出来
一般构建步骤:
- 先创建 ParameterExpression
- 接着由里到外逐步构建
- 先左节点(Left)
- 后右节点(Right)
- 接着Body节点
- 将其拼接成 Expression
public IActionResult GetUserByManualExpression()
{
ParameterExpression parameterExpression = Expression.Parameter(type:typeof(User), name: "u");
ConstantExpression right = Expression.Constant(18);
MemberExpression left = Expression.MakeMemberAccess(parameterExpression, member: typeof(User).GetProperty("Age"));
BinaryExpression body = Expression.GreaterThanOrEqual(left, right);
Expression<Func<User, bool>> expression = Expression.Lambda<Func<User, bool>>(body, parameters: parameterExpression);
var data = _userService.GetUsers(expression);
return Ok(new
{
code = 200,
msg = "OK",
data
});
}
[C# Expression] 之基础概念的更多相关文章
- JavaScript--我发现,原来你是这样的JS(基础概念--躯壳,不妨从中文角度看js)
介绍 这是红宝书(JavaScript高级程序设计 3版)的读书笔记第二篇(基础概念--躯壳篇),有着部分第三章的知识内容,当然其中还有我个人的理解.红宝书这本书可以说是难啃的,要看完不容易,挺厚的, ...
- JS--我发现,原来你是这样的JS(二)(基础概念--躯壳篇--不妨从中文角度看js)
一.介绍 这是红宝书(JavaScript高级程序设计 3版)的读书笔记第二篇(基础概念--躯壳篇),有着部分第三章的知识内容,当然其中还有我个人的理解. 红宝书这本书可以说是难啃的,要看完不容易,挺 ...
- 第214天:Angular 基础概念
一.Angular 简介 1. 什么是 AngularJS - 一款非常优秀的前端高级 JS 框架 - 最早由 Misko Hevery 等人创建 - 2009 年被 Google 公式收购,用于其多 ...
- 【Machine Learning】机器学习及其基础概念简介
机器学习及其基础概念简介 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...
- TCP/IP基础概念及通信过程举例
TCP/IP基础概念及通信过程举例 出现 上个世纪60年代,由于中央集中式网络的容灾性较弱,以美国国防部为中心的一家组织研究出分组交换网络.后来为了验证分组交换技术的实用性,ARPANET出现了,并且 ...
- Jmeter基础之---jmeter基础概念
Jmeter基础之---jmeter基础概念 JMeter 介绍: 一个非常优秀的开源的性能测试工具. 优点:你用着用着就会发现它的重多优点,当然不足点也会呈现出来. JMeter 介绍: 一个非常优 ...
- 快速入门系列--WCF--01基础概念
转眼微软的WCF已走过十个年头,它是微软通信框架的集大成者,将之前微软所有的通信框架进行了整合,提供了统一的应用方式.记得从自己最开始做MFC时,就使用过Named Pipe命名管道,之后做Winfo ...
- 理解 angular2 基础概念和结构 ----angular2系列(二)
前言: angular2官方将框架按以下结构划分: Module Component Template Metadata Data Binding Directive Service Dependen ...
- JavaBean 基础概念、使用实例及代码分析
JavaBean 基础概念.使用实例及代码分析 JavaBean的概念 JavaBean是一种可重复使用的.且跨平台的软件组件. JavaBean可分为两种:一种是有用户界面的(有UI的):另一种是没 ...
随机推荐
- Codeforces 605D - Board Game(树状数组套 set)
Codeforces 题目传送门 & 洛谷题目传送门 事实上是一道非常容易的题 很容易想到如果 \(c_i\geq a_j\) 且 \(d_i\geq b_j\) 就连一条 \(i\to j\ ...
- awk多文件处理时的分隔符?
目录 问题来源 解决方法 问题来源 我有两个文件,一个是plink过滤后得到的.fam文件(空格分隔):另一个是样本对应关系文件(tab分隔). 文件1: 文件2: 两个文件匹配,awk常规操作.这里 ...
- Mike post process with Matlab toolbox
表怕,这个博客只有题目是英文的-- Matlab toolbox 安装 去DHI官网下载最新的MikeSDK2014与Matlab toolbox,下载好后安装MikeSDK2014,注意电脑上不能有 ...
- Nginx pid文件找不到 nginx: [error] open() "/run/nginx/nginx.pid" failed (2: No such file or directory)
Nginx pid文件找不到 nginx: [error] open() "/run/nginx/nginx.pid" failed (2: No such file or dir ...
- 虚拟节点轻松应对 LOL S11 百万并发流量——腾竞体育的弹性容器实践
作者 刘如梦,腾竞体育研发工程师,擅长高并发.微服务治理.DevOps,主要负责电竞服务平台架构设计和基础设施建设. 詹雪娇,腾讯云弹性容器服务EKS产品经理,主要负责 EKS 虚拟节点.容器实例相关 ...
- 大数据学习----day27----hive02------1. 分桶表以及分桶抽样查询 2. 导出数据 3.Hive数据类型 4 逐行运算查询基本语法(group by用法,原理补充) 5.case when(练习题,多表关联)6 排序
1. 分桶表以及分桶抽样查询 1.1 分桶表 对Hive(Inceptor)表分桶可以将表中记录按分桶键(某个字段对应的的值)的哈希值分散进多个文件中,这些小文件称为桶. 如要按照name属性分为3个 ...
- 大数据学习day15----第三阶段----scala03--------1.函数(“_”的使用, 函数和方法的区别)2. 数组和集合常用的方法(迭代器,并行集合) 3. 深度理解函数 4 练习(用java实现类似Scala函数式编程的功能(不能使用Lambda表达式))
1. 函数 函数就是一个非常灵活的运算逻辑,可以灵活的将函数传入方法中,前提是方法中接收的是类型一致的函数类型 函数式编程的好处:想要做什么就调用相应的方法(fliter.map.groupBy.so ...
- CentOS7 安装配置RocketMQ --主从模式(master-slave)异步复制
机器信息 192.168.119.129 主 192.168.119.128 从 配置host[两台机器] vim /etc/hosts 添加 192.168.119.129 rocketmq-nam ...
- mybatis缓存+aop出现的问题
在对某些特殊数据进行转换时,getOne方法后执行fieleInfoHandle进行转换,如果直接使用fixedTableData进行操作,没有后续的二次调用这样是没问题的,但是在后面当执行完upda ...
- JVM——内存分配与回收策略
1.对象优先在Eden区分配 大多数情况下,对象在新生代Eden区分配.当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC. 虚拟机提供了 -XX:+PrintGCDetails这 ...