C#表达式树讲解
作者:痴者工良 发布时间:2023-02-23 19:22:52
表达式树的概念
表达式树的创建有 Lambda法 和 组装法。
学习表达式树需要 委托、Lambda、Func<> 基础。
表达式树 形状可以参考二叉树。
可以把表达式树理解成 数学表达式。
数学表达式的所有常量、符号为表达式树的底节点。每一次计算生成的结果是一个结点,或者说他们的共同结点就是他们应该进行的运算。
生成表达式树
表达式树的创建有 Lambda表达式法
和 组装法
为了方便,这里指定生成的表达式为 ( i * j ) + ( x * y )
他们的运算是这样的
Lambda 生成表达式树
在控制台创建应用,需要引入
using System.Linq.Expressions;
1,创建表达式
(系统自动把 Lambda表达式 转为表达式树,当然,不是所有的 Lambda表达式都能转为表达式树,详细请参考文章后面的“系统自动把 Lambda表达式 转为 表达式树” 一节)
Expression<Func<int, int, int, int, int>> func = (i, j, x, y) => (i * j) + (x * y);
2,输出系统转换的表达式
输入这一行代码后运行,看看控制台输出的表达式树
Console.WriteLine(func);
3,把代码转为数据
(把代码当作数据来使用)
var compile = func.Compile();
//或 Func<int, int, int, int, int> compile = func.Compile();
4,代入运算
int result = compile(12, 13, 14, 15); //把具体数字代入表达式并运算
Console.WriteLine(result); //输出表达式结果
完整代码如下
Expression<Func<int, int, int, int, int>> func = (i, j, x, y) => (i * j) + (x * y);
Console.WriteLine(func); //输出表达式
var compile = func.Compile(); //把代码转为数据
//或 Func<int, int, int, int, int> compile = func.Compile();
int result = compile(12, 13, 14, 15); //把具体数字代入表达式并运算
Console.WriteLine(result); //输出表达式结果
Console.ReadKey();
控制台输出
组装法生成表达式树
表达式由 "符号" 和 运算符组成,。
使用ParameterExpression
类型 来修饰参数,使用Expression.Parameter(Type type,string name)
实例化参数。
1,生成 a b d 参数
ParameterExpression a = Expression.Parameter(typeof(int), "i");
ParameterExpression b = Expression.Parameter(typeof(int), "j");
ParameterExpression c = Expression.Parameter(typeof(int), "x");
ParameterExpression d = Expression.Parameter(typeof(int), "y");
分析:
i、j、x、y是结点名称,a、b、c、d是实例名称。不用留精力思考我上面 a b c d i j x y 的名称设定。
ParameterExpression 表示创建一个节点,Parameter表示一个命名的参数表达式,详细请参考文章后面的 “Expression 参数分类”。
Expression.Parameter(Type type,string name) 表示这个节点的属性。
2,生成结点
Expression r1 = Expression.Multiply(a, b); //乘法运行
Expression r2 = Expression.Multiply(c, d); //乘法运行
分析:
创建了 ( i * j ) 和 ( x * y ) 两个运算
Multiply 表示不进行溢出检查的乘法运算。Expression 里有 85种 操作方法,更多加减乘除比较大小等操作在文章后面详细附上,参考 “ 运算操作符” 一节。
3,生成终结点
Expression result = Expression.Add(r1, r2); //相加
4,生成表达式树、转换、输出表达式树、代入数据进行运算
Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);
var com = func.Compile();
Console.WriteLine("表达式" + func);
Console.WriteLine(com(12, 12, 13, 13));
完整代码如下
ParameterExpression a = Expression.Parameter(typeof(int), "i");
ParameterExpression b = Expression.Parameter(typeof(int), "j");
Expression r1 = Expression.Multiply(a, b); //乘法运行
ParameterExpression c = Expression.Parameter(typeof(int), "x");
ParameterExpression d = Expression.Parameter(typeof(int), "y");
Expression r2 = Expression.Multiply(c, d); //乘法运行
Expression result = Expression.Add(r1, r2); //相加
//以上代码产生结点
//生成表达式
Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);
var com = func.Compile();
Console.WriteLine("表达式" + func);
Console.WriteLine(com(12, 12, 13, 13));
Console.ReadKey();
控制台界面
补充说明
1,系统自动把 Lambda表达式 转为 表达式树
对 lambda表达式 的要求 只能 由 传入参数 和 返回参数 两部分表示。lambda表达式 不能包含其它判断、循环等的代码。
错误举例
Expression<Func<int, int, int, int, int>> func = (a, b, c, d) =>
{
if (a < 10)
{
a += 1;
}
/*
* 其它操作代码
*/
return a + b + c + d;
};
把那些东西通通删除,修改后:
Expression<Func<int, int, int, int, int>> func = (a, b, c, d) => a + b + c + d;
这样的 “最简” 的 lambda表达式 才能被系统自动转为表达式树
2,运算操作符
一般数学上,有加减乘除、取余、求幂等操作,而在程序中,运算操作符可以有更多的选择,达 85 种。
笔者这里给出一张图列出部分方法。
微软官方 的操作运算符列表https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.expression?view=netframework-4.7.2
估计大家看微软的文档会有点不爽~这里推荐大神翻译、整理的列表https://www.jb51.net/article/234265.htm
3,Expression 参数
以数学椭圆周长公式:L = 2πb + 4(a-b) ,a 为长半轴,b 为短半轴, 进行举例
Parameter 类似于 数学的 未知数 如 a 、 b;使用方法
ParameterExpression a = Expression.Parameter(typeof(int), "a")
ParameterExpression b = Expression.Parameter(typeof(int), "b")
Constant 表示一个常数,例如2πb 中的 2 或者 2π;使用方法
ConstantExpression define = Expression.Constant(2);
其它更多参数分类 请查看https://www.jb51.net/article/234265.htm
这里附上部分截取图片
4,Expression 的操作方法
表示加减乘除等运算的方法。以下图举例
Multiply(a,b) 为乘法,Add(r1,r2)为加法。
当然,并没有这么简单,他们都有相关的重载方法和高级的使用用途。
请查看https://www.jb51.net/article/234265.htm
这里给出部分截图
5,表达式树的高级用法
表达式树可以结合 数据库查询 或 Linq,衍生很多高级操作。
例如 动态查询、遍历表达式树、转成成SQL where 子句等等,限于幅度,笔者不再赘述。
下面的链接可以查看 System.Linq.Expressions 的所有类型对象。https://docs.microsoft.com/zh-cn/dotnet/api/System.Linq.Expressions?view=netframework-4.7.2
来源:https://www.cnblogs.com/whuanle/p/10039237.html


猜你喜欢
- 前言简单来说机器学习的核心步骤在于“获取学习数据;选择机器算法;定型模型;评估模型,预测模型结果”,下面本人就以判断日报内容是否合格为例为大
- 开放端口安全组没开放端口是原罪!!!导致好多BUG费时费力。Hbase悄悄 * 的用了好多端口,比如被我抓到的42239,直接搜索报错药不对症
- 网上很多人对设置控件的位置都使用view.setPadding(left, top, right, bottom) ,其实这玩意很差劲,它是
- 支付宝今年推出了新的转账接口alipay.fund.trans.uni.transfer(升级后安全性更高,功能更加强大) ,老转账接口al
- 1. 关于POJO类属性为基本类型存在的问题在项目开发中遇到的问题,定义POJO类的时候有些属性定义为了基本数据类型,比如long,shor
- 重新启动IDEA maven项目SSM框架所有@注解失效,每个文件上都有个小黄圆,而且我发现所有构建项目的maven的jar包都不在了,也就
- 【前言】AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统
- 本文实例讲述了C#使用foreach语句简单遍历数组的方法。分享给大家供大家参考。具体如下:using System;public clas
- 日常工作中 Map 绝对是我们 Java 程序员高频使用的一种数据结构,那 Map 都有哪些遍历方式呢?这篇文章阿粉就带大家看一下,看看你经
- 1.什么是并行计算传统并行计算:共享同一个数据,通过锁来控制数据的读写,难度大,容易导致死锁,拓展性差。但是是实时的,细颗粒度计算,计算密集
- MyBatis源码解析_获取SqlSessionFactory我们都知道,在Mybatis中,对数据库的增删改查,实际上是由SqlSessi
- 一、首先编写一个工具类Hello:public class Hello { public static void say(Str
- 本文实例为大家分享了Java NIO实战之多人聊天室的具体代码,供大家参考,具体内容如下NIO服务端public class NioServ
- 本文实例为大家分享了OpenGL绘制Bezier曲线的具体代码,供大家参考,具体内容如下项目要求:– 使用鼠标在屏幕中任意设置控制点,并生成
- JSR303 是一套 JavaBean 参数校验的标准1、pom导入依赖<dependency><groupId>o
- 一.摘要emmmm..对springmvc不太熟练的情况下,如果不出意外的话,项目启动后出现404页面是很烦人。在这里,我记录一下可能会导致
- JAVA可以通过反射获取成员变量和静态变量的名称,局部变量就不太可能拿到了。public class Test {public static
- 方法一:Handler+Threadpackage com.xunfang.handerDemo; import android.app.A
- 前言本文主要介绍了关于spring boot中servlet启动过程与原理的相关内容,下面话不多说了,来一起看看详细的介绍吧启动过程与原理:
- Android中子线程和UI线程之间通信的详细解释 1.在多线程编程这块,我们经常要使用Handler,Thread和Runnable这三个