C#3.0新增功能10 表达式树 02 说明
表达式树是定义代码的数据结构。 它们基于编译器用于分析代码和生成已编译输出的相同结构。表达式树和 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)
- 隐式 var 关键字 (
- 二进制加法表达式 (
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 对象,而不是依赖于编译器支持。 另一个示例是创建循环。 通常,通过使用 for、foreach、while 或 do 循环对其进行创建。 正如稍后可以在本系列中看到的那样,表达式树的 API 支持单个循环表达式,该表达式包含控制重复循环的 break 和 continue 表达式。
不能执行的操作是修改表达式树。 表达式树是不可变的数据结构。 如果想要改变(更改)表达式树,则必须创建基于原始树副本但包含所需更改的新树。
C#3.0新增功能10 表达式树 02 说明的更多相关文章
- C#3.0新增功能10 表达式树 05 解释表达式
连载目录 [已更新最新开发文章,点击查看详细] 表达式树中的每个节点将是派生自 Expression 的类的对象. 该设计使得访问表达式树中的所有节点成为相对直接的递归操作. 常规策略是从根节点 ...
- C#3.0新增功能10 表达式树 07 翻译(转换)表达式
连载目录 [已更新最新开发文章,点击查看详细] 本篇将介绍如何访问表达式树中的每个节点,同时生成该表达式树的已修改副本. 以下是在两个重要方案中将使用的技巧. 第一种是了解表达式树表示的算法,以 ...
- C#3.0新增功能10 表达式树 01 简介
连载目录 [已更新最新开发文章,点击查看详细] 如果你使用过 LINQ,则会有丰富库(其中 Func 类型是 API 集的一部分)的经验. (如果尚不熟悉 LINQ,建议阅读 LINQ 教程,以 ...
- C#3.0新增功能10 表达式树 03 支持表达式树的框架类型
连载目录 [已更新最新开发文章,点击查看详细] 存在可与表达式树配合使用的 .NET Core framework 中的类的大型列表. 可以在 System.Linq.Expressions 查 ...
- C#3.0新增功能10 表达式树 06 生成表达式
连载目录 [已更新最新开发文章,点击查看详细] 到目前为止,你所看到的所有表达式树都是由 C# 编译器创建的. 你所要做的是创建一个 lambda 表达式,将其分配给一个类型为 Expressi ...
- C#3.0新增功能10 表达式树 04 执行表达式
连载目录 [已更新最新开发文章,点击查看详细] 表达式树 是表示一些代码的数据结构. 它不是已编译且可执行的代码. 如果想要执行由表达式树表示的 .NET 代码,则必须将其转换为可执行的 IL ...
- C#3.0新增功能09 LINQ 基础02 LINQ 查询简介
连载目录 [已更新最新开发文章,点击查看详细] 查询 是一种从数据源检索数据的表达式. 查询通常用专门的查询语言来表示. 随着时间的推移,人们已经为各种数据源开发了不同的语言:例如,用于关系数据 ...
- C#基础拾遗系列之二:使用ILSpy探索C#7.0新增功能点
C#基础拾遗系列之二:使用ILSpy探索C#7.0新增功能点 第一部分: C#是一种通用的,类型安全的,面向对象的编程语言.有如下特点: (1)面向对象:c# 是面向对象的范例的一个丰富实现, 它 ...
- C#2.0新增功能06 协变和逆变
连载目录 [已更新最新开发文章,点击查看详细] 在 C# 中,协变和逆变能够实现数组类型.委托类型和泛型类型参数的隐式引用转换. 协变保留分配兼容性,逆变则与之相反. 以下代码演示分配兼容性.协 ...
随机推荐
- 进程交互还可以使用QSharedMemory
官方例子: http://doc.qt.io/qt-5/qtcore-ipc-sharedmemory-example.html 查了一下,QSharedMemory没有自带任何信号.我的想法: 1. ...
- 通过使用URLEncoder与URLDecoder进行编码和解码
使用改方法必须导入 java.net包 <%@page import="java.net.*" %> 编码: 当要存储或者发送数据的时候使用,将编码后的字符串再发送或者 ...
- Windows窗体原理及控件WM_DRAWITEM和子类化重绘演示文件
http://download.csdn.net/detail/wenzhou1219/6783959
- 关于客户端javascript的理解及事件浅析
1,核心JavaScript和客服端JavaScript都有一个单线程执行模型.脚本和事件处理程序在同一时间只能执行一个,没有并发性.这样保持了js编程的简单性. 2,document的定义:一些呈现 ...
- python中的命名空间以及函数的嵌套
一.动态传参 函数的形参中除了默认值参数和位置参数外,还有动态传参.当不确定形参有几个或者有很多的时候,就可以使用动态传参. 1.1 动态接收位置参数 在python中使用*来接收动态位置参数 def ...
- C#中await/async闲说
自从C#5.0增加异步编程之后,异步编程越来越简单,async和await用的地方越来越多,越来越好用,只要用异步的地方都是一连串的异步,如果想要异步编程的时候,需要从底层开始编写,这样后边使用的时候 ...
- mysql-5.7.24-winx64安装与Navicat_for_MySQL_10.1.7注册码
mysql安装图解:https://blog.csdn.net/qq_38455201/article/details/83419450 Navicat注册码名:组织:注册码:均为NAVN-LNXG- ...
- 高并发 Nginx+Lua OpenResty系列(5)——Lua开发库Redis
Redis客户端 lua-resty-redis是为基于cosocket API的ngx_lua提供的Lua redis客户端,通过它可以完成Redis的操作.默认安装OpenResty时已经自带了该 ...
- 报错:java.sql.SQLException: The server
报错:java.sql.SQLException: The server time zone value '�й���ʱ��' is unrecognized 在IDEA运行是报出例如相识的错误时: ...
- Python自学day-14
一.默认创建的HTML5文件 <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...