什么是表达式树

来自微软官方文档的定义:

表达式树以树形数据结构表示代码。

它能干什么呢?

你可以对表达式树中的代码进行编辑和运算。这样能够动态修改可执行代码、在不同数据库中执行 LINQ 查询以及创建动态查询。

好不好玩?

表达式树还能用于动态语言运行时 (DLR) 以提供动态语言和 .NET Framework 之间的互操作性,同时保证编译器编写员能够发射表达式树而非 Microsoft 中间语言 (MSIL)。

哪里有应用?

ORM框架、工作流框架等,使用到 Lambda 的代码。。。动态执行代码、动态组装代码等。

创建表达式树

创建表达式树有两种方式:通过 lambda 表达式、通过 API。

创建表达式树的意思是,在此之前已经编写好每个结点,最后使用代码将所有结点组合起来,生成表达式树。

示例(通过API创建表达式树)

```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();

上面关于表达式树的代码很多,以下这一步叫生成/创建表达式树。

            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();

其它代码是用于生成表达式树结点/逻辑。

回归正题,创建表达式树的两种方法。

lambda 创建表达式树

上面的表达式树示例,是用于生成

 ( i * j ) + ( x * y )

但是就这么简单的操作,要写这么长,实在不合理。

而通过 lambda ,可以这样写

           Expression<Func<int, int, int, int, int>> func = (i, j, x, y) => (i * j) + (x * y);

如果使用 lambda 生成表达式树, lambda 只能使用单行语句,不能使用 if、for等语句。

具体关于 Lambda 的表达式树,后面其它文章有说明。

通过 API 创建表达式树

就是这样

Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);

两种方式左边的都是一样的,区别在于等号右边。

Expression< TDelegate >

上面示例的最终结果都是生成

Expression<Func<int, int, int, int, int>> func 

func 是表达式树变量。

我们可以了解以下表达式树具有的方法和属性。

用于生成表达式树结点的,是 Expression 类型。

那么,创建的表达式树 func ,是 Expression<TDelegate>类型。

定义如下

public sealed class Expression<TDelegate> : LambdaExpression

具有方法如下

Compile() 将表达式树描述的 lambda 表达式编译为可执行代码,并生成表示 lambda 表达式的委托。
Compile(Boolean) 将表达式树描述的 Lambda 表达式编译为已解释或已编译的代码,并生成表示该 Lambda 表达式的委托。
Compile(DebugInfoGenerator) 将 lambda 编译到方法定义中。(Inherited from LambdaExpression)
Update(Expression, IEnumerable) 创建一个与此表达式类似的新表达式,但使用所提供的子级。如果所有子级都相同,则将返回此表达式。
Accept(ExpressionVisitor) 调度到此节点类型的特定 Visit 方法。例如,MethodCallExpression调用 VisitMethodCall。

由于 Expression<TDelegate> 继承了 LambdaExpression,所以有很多属性方法也可以用。

CanReduce 指示可将节点简化为更简单的节点。如果返回 true,则可以调用 Reduce() 以生成简化形式。
Name 获取 lambda 表达式的名称。
NodeType 返回此 Expression 的节点类型。
Parameters 获取 lambda 表达式的参数。
ReturnType 获取 lambda 表达式的返回类型。
TailCall 获取一个值,该值指示是否将通过尾调用优化来编译 lambda 表达式。
Type 获取此 Expression 表示的表达式的静态类型。

好了,以上权当小笔记,备忘,目前先用不上,后面慢慢来使用。

解析/执行表达式树

创建表达式树后,就要执行表达式树。

在此之前,你需要了解 委托 Delegate,Func,Action,以及他们中间的关系。

执行表达式树是这样子的

            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();var runRasult = com(12, 12, 13, 13);

func 只是一个表达式树,我们把表达式树构建好后,“要将表达式树转为代码”,使用

.Compile() 方法,可以将表达式树生成一个 委托(例如上面的 com)。

为了简洁上面使用了 var,实际上是这样的

            Func<int,int,int,int,int> com = func.Compile();

四个参数,一个返回值。

var runRasult = com(12, 12, 13, 13);

C#里有语法糖,对委托可以这样写

以后后面都是这样写了,能够缩成一行的代码,就没必要写出两行。

在 Vs 里面调试和查看表达式树,可以看这里

https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/expression-trees/debugging-expression-trees-in-visual-studio

初学者不必纠结于这些,了解一下本文内容,记一下概要信息即可。

表达式树练习实践:入门基础相关推荐

  1. python 从入门到实践 pdf_python入门基础实践课,带你有效的学习python

    你还在枯燥的一个人学python吗?你尝试过python入门基础实践课吗? python入门实践课,带你快速了解python,它与你平时学python,有什么不一样的地方呢: 1.完全免费 第一次学p ...

  2. 3.Jenkins入门基础使用与Maven+SonarQube集成配置与实践

    目录一览: Maven 集成配置与实践 ​SonarQube 集成配置与实践 WeiyiGeek Blog - 为了能到远方,脚下的每一步都不能少. Tips : 本文章来源 Blog 站点或者 We ...

  3. NVIDIA DLI——深度学习基础-理论与实践入门

    今天参加了 NVIDIA DLI课程,主要学习基础理论,并进行实践. 深度学习理论与实践入门培训 | NVIDIAhttps://www.nvidia.cn/training/instructor-l ...

  4. 4.Jenkins入门基础使用与邮箱钉钉微信消息通知集成配置与实践

    WeiyiGeek Blog - 为了能到远方,脚下的每一步都不能少. Tips : 本文章来源 Blog 站点或者 WeiyiGeek 公众账号 (技术交流.友链交换请邮我哟), 原文地址: 4.J ...

  5. python爬虫实践——零基础快速入门(四)爬取小猪租房信息

    上篇文章我们讲到python爬虫实践--零基础快速入门(三)爬取豆瓣电影 接下来我们爬取小猪短租租房信息.进入主页后选择深圳地区的位置.地址如下: http://sz.xiaozhu.com/ 一,标 ...

  6. envi 文件 生成mat_JVM 内存分析工具 MAT 的深度讲解与实践——入门篇

    1. MAT 工具简介 MAT(全名:Memory Analyzer Tool),是一款快速便捷且功能强大丰富的 JVM 堆内存离线分析工具.其通过展现 JVM 异常时所记录的运行时堆转储快照(Hea ...

  7. 深入入门正则表达式(java) - 1 - 入门基础

    深入入门正则表达式(java) - 引言 深入入门正则表达式(java) - 1 - 入门基础  深入入门正则表达式(java) - 2 - 基本实例 深入入门正则表达式(java) - 3 - 正则 ...

  8. Java入门基础及面试100题--初入门

    Java入门基础及面试100题 注:适合应届毕业生或java初入门者 1.面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: - 抽象:抽象是将一类对象的共同特征总结出来构造类的过程, ...

  9. 【无标题】C#nbsp;语言入门基础介绍学习通http://www.bdgxy.com/

    文章来源: 学习通http://www.bdgxy.com/ 普学网http://www.boxinghulanban.cn/ 智学网http://www.jaxp.net/ 表格制作excel教程h ...

最新文章

  1. mysql 大量数据 更改索引_Mysql索引数据结构详解与索引优化
  2. xfs_repair 实际工作中的问题
  3. 测试香港服务器访问速度的方法
  4. linux nohup 终端断了,linux 后台执行nohup 命令,终端断开无影响
  5. Mac 编译报错 symbol(s) not found for
  6. QT中的QGridLayout布局
  7. MySQL的隔离级别
  8. Android的线程使用来更新UI----Thread、Handler、Looper、Time...
  9. 的不定积分_不定积分大集合——方法篇
  10. python标准库之random模块
  11. Linux学习---新建文件,查看文件,修改权限,删除
  12. NO JVM installation found. please install a 64-bit JDK,解决方法   Error launching android studio   NO J
  13. 柳絮飘,往事忆:家(二)
  14. 微型计算机原理顺序程序设计,微机原理实验,顺序实验.docx
  15. php自定义文件后缀名,显示文件扩展名 显示文件后缀名设置篇-DIV CSS网页开发准备...
  16. 算法导论程序24--直接寻址表(Python)
  17. 基于Java毕业设计畜牧场信息管理系统源码+系统+mysql+lw文档+部署软件
  18. Linux永久修改主机名和IP
  19. c libxml2解析html,在Python中,lxml和libxml2哪个更适合解析格式错误的html?
  20. html5 混合地址,混合引用是指在一个引用的单元格地址中的什么?

热门文章

  1. Wave 文件(5): 获取 Wave 文件的格式信息
  2. 连续对焦 auto对焦_如何在Windows 10上使用对焦辅助(请勿打扰模式)
  3. outlook附件大小限制_如何在Outlook中调整大图片附件的大小
  4. Java8基础之super关键字
  5. Java8新特性--CompletableFuture
  6. stl中Priority Queues(优先队列)的基本用法
  7. WiFi行业将走向何方?
  8. JavaScript匿名函数以及在循环中的匿名函数
  9. protobuf在java应用中通过反射动态创建对象
  10. Cowboy 源码分析(十八)