表达式树是定义代码的数据结构。 它们基于编译器用于分析代码和生成已编译输出的相同结构。表达式树和 Roslyn API 中用于生成分析器和 CodeFixes 的类型之间存在很多相似之处。 (分析器和 CodeFixes 是 NuGet 包,用于对代码执行静态分析,并可为开发人员建议可能的修补程序。)两者概念相似,且最终结果是一种数据结构,该结构允许以有意义的方式对源代码进行检查。 但是,表达式树基于一组与 Roslyn API 完全不同的类和 API。

让我们来举一个简单的示例。 以下是一个代码行:

var sum =  + ;

如果要将其作为一个表达式树进行分析,则该树包含多个节点。 最外面的节点是具有赋值 (var sum = 1 + 2;) 的变量声明语句,该节点包含若干子节点:变量声明、赋值运算符和一个表示等于号右侧的表达式。 该表达式被进一步细分为表示加法运算、该加法左操作数和右操作数的表达式。

让我们稍微深入了解一下构成等于号右侧的表达式。 该表达式是 1 + 2。 这是一个二进制表达式。 更具体地说,它是一个二进制加法表达式。 二进制加法表达式有两个子表达式,表示加法表达式的左侧和右侧节点。 此处的两个节点都是常量表达式:左操作数是值 1,右操作数是值 2

直观地看,整个语句是一个树:应从根节点开始,遍历到树中的每个节点,以查看构成语句的代码:

  • 具有赋值 (var sum = 1 + 2;) 的变量声明语句

    • 隐式变量类型声明 (var sum)赋值运算符 (=)

      • 隐式 var 关键字 (var)
      • 变量名称声明 (sum)
    • 二进制加法表达式 (1 + 2)
      • 左操作数 (1)
      • 加法运算符 (+)
      • 右操作数 (2)

这可能看起来很复杂,但它功能强大。 按照相同的过程,可以分解更加复杂的表达式。 请思考此表达式:

var finalAnswer = this.SecretSauceFunction(currentState.createInterimResult(),
currentState.createSecondValue(, ),
decisionServer.considerFinalOptions("hello")
)
+ MoreSecretSauce('A', DateTime.Now, true);

上述表达式也是具有赋值的变量声明。 在此情况下,赋值的右侧是一棵更加复杂的树。 我不打算分解此表达式,但请思考一下不同的节点可能是什么。 存在使用当前对象作为接收方的方法调用,其中一个调用具有显式 this 接收方,一个调用不具有此接收方。 存在使用其他接收方对象的方法调用,存在不同类型的常量参数。 最后,存在二进制加法运算符。 该二进制加法运算符可能是对重写的加法运算符的方法调用(具体取决于 SecretSauceFunction() 或 MoreSecretSauce() 的返回类型),解析为对为类定义的二进制加法运算符的静态方法调用。

尽管具有这种感知上的复杂性,但上面的表达式创建了一种树形结构,可以像第一个示例那样轻松地导航此结构。 可以保持遍历子节点,以查找表达式中的叶节点。 父节点将具有对其子节点的引用,且每个节点均具有一个用于介绍节点类型的属性。

表达式树的结构非常一致。 了解基础知识后,你甚至可以理解以表达式树形式表示的最复杂的代码。 优美的数据结构说明了 C# 编译器如何分析最复杂的 C# 程序并从该复杂的源代码创建正确的输出。

熟悉表达式树的结构后,你会发现通过快速获得的知识,你可处理许多越来越高级的方案。 表达式树的功能非常强大。

除了转换算法以在其他环境中执行之外,表达式树还可用于在执行代码前轻松编写检查代码的算法。 可以编写参数为表达式的方法,然后在执行代码之前检查这些表达式。 表达式树是代码的完整表示形式:可以看到任何子表达式的值。 可以看到方法和属性名称。 可以看到任何常数表达式的值。 还可以将表达式树转换为可执行的委托,并执行代码。

通过表达式树的 API,可创建表示几乎任何有效代码构造的树。 但是,出于尽可能简化的考虑,不能在表达式树中创建某些 C# 习惯用语。 其中一个示例就是异步表达式(使用 async 和 await关键字)。 如果需要异步算法,则需要直接操作 Task 对象,而不是依赖于编译器支持。 另一个示例是创建循环。 通常,通过使用 forforeachwhile 或 do 循环对其进行创建。 正如稍后可以在本系列中看到的那样,表达式树的 API 支持单个循环表达式,该表达式包含控制重复循环的 break 和 continue 表达式。

不能执行的操作是修改表达式树。 表达式树是不可变的数据结构。 如果想要改变(更改)表达式树,则必须创建基于原始树副本但包含所需更改的新树。

C#3.0新增功能10 表达式树 02 说明的更多相关文章

  1. C#3.0新增功能10 表达式树 05 解释表达式

    连载目录    [已更新最新开发文章,点击查看详细] 表达式树中的每个节点将是派生自 Expression 的类的对象. 该设计使得访问表达式树中的所有节点成为相对直接的递归操作. 常规策略是从根节点 ...

  2. C#3.0新增功能10 表达式树 07 翻译(转换)表达式

    连载目录    [已更新最新开发文章,点击查看详细] 本篇将介绍如何访问表达式树中的每个节点,同时生成该表达式树的已修改副本. 以下是在两个重要方案中将使用的技巧. 第一种是了解表达式树表示的算法,以 ...

  3. C#3.0新增功能10 表达式树 01 简介

    连载目录    [已更新最新开发文章,点击查看详细] 如果你使用过 LINQ,则会有丰富库(其中 Func 类型是 API 集的一部分)的经验. (如果尚不熟悉 LINQ,建议阅读 LINQ 教程,以 ...

  4. C#3.0新增功能10 表达式树 03 支持表达式树的框架类型

    连载目录    [已更新最新开发文章,点击查看详细] 存在可与表达式树配合使用的 .NET Core framework 中的类的大型列表. 可以在 System.Linq.Expressions 查 ...

  5. C#3.0新增功能10 表达式树 06 生成表达式

    连载目录    [已更新最新开发文章,点击查看详细] 到目前为止,你所看到的所有表达式树都是由 C# 编译器创建的. 你所要做的是创建一个 lambda 表达式,将其分配给一个类型为 Expressi ...

  6. C#3.0新增功能10 表达式树 04 执行表达式

    连载目录    [已更新最新开发文章,点击查看详细] 表达式树 是表示一些代码的数据结构. 它不是已编译且可执行的代码. 如果想要执行由表达式树表示的 .NET 代码,则必须将其转换为可执行的 IL ...

  7. C#3.0新增功能09 LINQ 基础02 LINQ 查询简介

    连载目录    [已更新最新开发文章,点击查看详细] 查询 是一种从数据源检索数据的表达式. 查询通常用专门的查询语言来表示. 随着时间的推移,人们已经为各种数据源开发了不同的语言:例如,用于关系数据 ...

  8. C#基础拾遗系列之二:使用ILSpy探索C#7.0新增功能点

    C#基础拾遗系列之二:使用ILSpy探索C#7.0新增功能点   第一部分: C#是一种通用的,类型安全的,面向对象的编程语言.有如下特点: (1)面向对象:c# 是面向对象的范例的一个丰富实现, 它 ...

  9. C#2.0新增功能06 协变和逆变

    连载目录    [已更新最新开发文章,点击查看详细] 在 C# 中,协变和逆变能够实现数组类型.委托类型和泛型类型参数的隐式引用转换. 协变保留分配兼容性,逆变则与之相反. 以下代码演示分配兼容性.协 ...

随机推荐

  1. 解析 Qt 字库移植并能显示中文 (下篇)

    原文http://mobile.51cto.com/symbian-272563.htm 本文介绍的是Qt 字库移植并能显示中文,需要的字体库文件,一般是多个.具体移植那一个,看你使用的字库是什么了, ...

  2. 一次C#和C++的实际应用性能比较(C++允许我们使用任何手段来提高效率,只要愿意做出足够的努力)

    05年时,在微软的Rico Mariani做了一次实际应用的C#和C++的性能比较.事情起源于微软著名的元老Raymond Chen(在下敬仰的超级牛人)用C++写了一个英汉词典程序,来描述讲解优化C ...

  3. 小抄:选择 Unity 的对象生命周期管理员

    Unity 框架提供了数种生命周期管理员,各有相同和相异之处.刚开始接触时,难免头昏. 制作这张小抄,只是为了要帮助自己理解和记忆.如果你也用 Untiy,或可参考看看. 文字說明: Transien ...

  4. xmanager小技巧

    使用manager时候,左键选中之后,直接右键粘贴,能带来效率的提升.虽然是小技巧,但有人还是不知道,这里简单写一下,供需要的同学参考. 简单二步设置: 1.工具-选项

  5. Servlet 3.0异步特性初探

    Servlet 是 Java 为了编写服务端程序而定义的一个接口规范,在 Servlet 3.0 以后支持了异步的操作. 最近项目添加了一个代码热部署的功能,在客户端输入信号,信号到达 Web 服务器 ...

  6. 《菜鸟也要学会C》-和大家聊一聊

    简介 为什么要出本系列作品? 怎么学好C? 学完这套课程后,我的编程会怎么样? 1.1为什么要出本系列作品? 随着大部分人喜欢编程,大部分人都有一个毛病,就是想要急切的学完编程.其实这种思想是错误的, ...

  7. 直播技术:从性能参数到业务大数据,浅谈直播CDN服务监控

    线上服务的有效监控和数据收集,一直是后端服务离不开的话题.直播作为一种经典的分布式系统,监控以及数据收集更是必不可少的工作.如何对海量的服务集群有效的监控和保活,又如何抓取集群中的碎片数据中来优化服务 ...

  8. java源码解析之String类(三)

    上一节我们主要讲了String类的一些不是很常用的方法,其中需要掌握的如下,我就不再赘述了 public int length() public boolean isEmpty() public by ...

  9. 系统学习 Java IO (八)----装饰流 FilterInputStream/FilterOutputStream

    目录:系统学习 Java IO---- 目录,概览 这两个流的作用是:"封装其它的输入流,并为它们提供额外的功能" 他们的直接子类有: BufferedInputStream 的作 ...

  10. 【jar包管理】Maven BOM

    BOM Alibaba Spring Boot Dependencies is a Maven BOM used to manage the versions of most used Alibaba ...