开始写第四篇,别的不说了。这篇将涉及到如何使用字符串解析结果,生成一个 Lambda 表达式树。东西有点多,我先整理一下思路,在下面说明一下。如果你有问题,在后面的评论上写下来,我看到了会回复你。

在前几篇中,我写了一个字符串解析模块,还有一个根据字符串解析成 Type 对象的类型分析模块。这两个模块,都将为这个 Expression 核心解析类提供辅助,所以如果前两篇文章你没有看到,可以到我博客中先把前几篇文章看一下,理解我的整体思路后,再回过头来看这篇。

我希望从这篇文章开始,看到一些有用的评论,谢谢了!

Expression 核心解析类(ExpressionParserCore)对外发布的只有一个方法 —— ToLambdaExpression ,用于输出分析得到的 Lambda 表达式树。在贴代码之前,我把大致思路说明一下:

首先,需要几个前提条件:

1.  待分析的字符串

2.  Lambda 表达式树包含的委托类型

3.  类型解析可能用到的命名空间和程序集列表

第一个,很好理解,在这里不做阐述。

第二个,是告诉要解析的目标参数和返回值信息。

第三个,类型解析中会用到,这里只是做一下参数传递。具体的代码可以参看第三篇。

其次,由于 Lambda 表达式树的递归特性,所以其解析工作不可能一蹴而就,所以解析工作将其拆分为三步:

1.  ReadFirstExpression

2.  ReadNextExpression

3.  ReadExpression

从字面上可以看出来:ReadFirstExpression 是读取第一个 Expression ,ReadNextExpression 是读取接下来的 Expression ,ReadExpression 是读取 Expression 。

ReadFirstExpression:读取第一个 Expression ,不去管后面是不是还有没有解析的 Expression 。比如:【() => 1 + 2】这个表达式,如果使用该方法则只会读取常量表达式【1】,不会继续读取剩下的常量表达式【2】和加法表达式。一句话总结:读取了一个 Expression 就停止读取。

ReadNextExpression:读取下一个 Expression ,在已读取了表达式的基础上继续解析 Expression 。接着上面的表达式【() => 1 + 2】继续说,读取了表达式【1】后,继续读取常量表达式【2】,再继续读取加法表达式,返回整个表达式。

到了这里,有人会问:为什么会分成读取第一个和读取下一个两个方法?有以下原因吧,我感觉分开好些:

1.  有些表达式不能作为第一个表达式(比如加法表达式),有些不能作为后续的表达式(比如求反表达式)。

2.  就是有些符号不能在开始表达式中(比如右括号),有些不能作为在结束表达式中(比如左括号)。

3.  开始表达式从零构造一个表达式,后续表达式需要一个前置表达式。

还有一些,暂时想到的就这些了。

ReadExpression:读取表达式,可以递归调用实现 Expression 的递归。在发布的方法 ToLambdaExpression 中,调用的就是 ReadExpression ,进行第一次的递归操作。在表达式中如果需要,可能会多次调用,比如表达式【() => 1 + 2】会调用两次:一次是开始调用 ToLambdaExpression 的时候,一次是解析常量表达式【2】的时候。

在此,我把大概的流程用【() => 1 + 2】说明一下吧:

1.  准备前提条件。

2.  将字符串【() => 1 + 2】解析为我们需要的 Token 单元集合。

3.  分析目标委托类型(可以理解为 typeof(Func<int>).GetType() )为 0 个参数,返回值为 int 的委托。

4.  调用 ToLambdaExpression 开始解析 Lambda 表达式树:第一次调用 ReadExpression 方法。

5.  ReadExpression 方法调用 ReadFirstExpression 方法获取一个常量表达式树【1】。

6.  ReadExpression 方法继续调用 ReadNextExpression 方法,并传递参数常量表达式树【1】。

7.  读取到加法表达式树,将常量表达式树【1】作为加法左边的表达式树,尚需要的右边表达式树,调用 ReadExpression 方法读取。

8.  ReadExpression 方法调用 ReadFirstExpression 方法获取一个常量表达式树【2】。

9.  ReadExpression 方法继续调用 ReadNextExpression 方法,并传递参数常量表达式树【2】。

10. 发现已经读取到末尾,ReadNextExpression 方法返回传递进来的参数常量表达式树【2】。

11. ReadExpression 返回读取到的常量表达式【2】,这里将返回到第 7 步。

12. 加法表达式的左右表达式均已具备,构造加法表达式【1 + 2】,并返回到第 6 步。

13. 继续读取发现读取到末尾,返回加法表达式【1 + 2】到第 4 步。

14. 根据委托类型构造 Lambda 表达式树并返回,解析完成。

我先将这三个方法的原型说明一下:

1.  ReadFirstExpression()

2.  ReadNextExpression(int level, ReadResult previousResult, TokenId? wrapStart = null)

3.  ReadExpression(int level = 0)

level         : 这个参数是运算符优先级,优先级越大该数字越大,比如【1 + 2 * 3】这个表达式,会先进行【2 * 3】的组合而不是【1 + 2】的组合。

previousResult: 表示前面分析得到的结果。包含两个属性:表达式和是否读取结束。

wrapStart     : 表示读取下一个表达式的前导 Token 类型。previousResult 中的属性【是否读取结束】和这个参数相关:每种括号的开始和结束对应。

就到这里吧,写太长了,估计多数人没看下去的兴趣。下篇我会把 ReadFirstExpression 方法的逻辑整理一下,顺便贴出来部分代码。如果你感觉我写的东西有用,或者你期待下一篇,请点一下推荐,谢谢了!

转载于:https://www.cnblogs.com/lenic/archive/2012/06/26/2563559.html

共享一个从字符串转 Lambda 表达式的类(4)相关推荐

  1. 共享一个从字符串转 Lambda 表达式的类(3)

    承上篇的思路继续写,这次介绍字符串转 Type 的方式--类型分析.我的思路是把 Type 解析由"TestNet.Person, TestNet, Version=1.0.0.0, Cul ...

  2. 拼接 字符串使用 Lambda 表达式

    拼接 字符串 String value = memberRankList.stream().map(MemberRanking -> MemberRanking.getRowIndex().to ...

  3. Java8 Lambda 表达式官方文档

    本文是对官方文档的不完全翻译,如有错误请指正. Lambda 表达式 匿名类的实现非常简单,例如只包含一个方法的接口,在这些情况下,您通常会尝试将函数作为参数传递给另一个方法,例如当有人单击按钮时应采 ...

  4. Java8 Lambda表达式语法和示例

    本文是对官方文档(https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)的概括总结,更详细的内容请看官方 ...

  5. Java学习记录五(多线程、网络编程、Lambda表达式和接口组成更新)

    Java学习记录五(多线程.网络编程.Lambda表达式和接口组成更新) Java 25.多线程 25.1实现多线程 25.1.1进程 25.1.2线程 25.1.3多线程的实现 25.1.4设置和获 ...

  6. java 8 lambda reduce_JDK8新特性Lambda表达式体验

    "Lambda 表达式"(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstra ...

  7. 10个Java 8 Lambda表达式经典示例

    Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表 达式,它将允许我们将行为传到函数里.在J ...

  8. Java Lambda表达式入门

    本文转自:http://blog.csdn.net/renfufei... 转载请注明出处 原文链接: Start Using Java Lambda Expressions 下载示例程序 Examp ...

  9. java拉姆达表达式事例,Java Lambda表达式详解和实例

    简介 Lambda表达式是Java SE 8中一个重要的新特性.lambda表达式允许你通过表达式来代替功能接口. lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体( ...

最新文章

  1. CSS 会被继承的属性
  2. 全球及中国胶合板行业产量规模与营运能力研究报告2022版
  3. python 禁用网卡_如何编程实现启用禁用网卡
  4. es6 Promise.race()方法
  5. C#2.0泛型中的变化: default 关键字
  6. python logger_Python:logging 的巧妙设计!
  7. ssh无密码登录设置方法以及出现问题 ECDSA host key 和IP地址对应的key不同的解决...
  8. 浙江省单考单招计算机提前招,2018浙江省各校高职提前招生简章汇总及深度解析...
  9. 可行性分析报告-学生信息管理系统
  10. vs2010学习版安装与激活
  11. 怎么防治计算机病毒,计算机病毒怎么防治
  12. 数据库——设计实体联系图
  13. 计算机数学位数,有效位数
  14. Python之遍历文件夹图片并重命名
  15. 彻底搞懂vertical-align 底线、基线、中线的含义
  16. 正则表达式之前瞻后顾
  17. win10 无法正常启动mindmanager 思维导图
  18. _tsplitpath_s(分解路径)
  19. UVa Problem 123 - Searching Quickly
  20. unity中打包APP显示手机最顶端的状态栏

热门文章

  1. 小凡模拟器使用视频(续)
  2. 关于PyCharm无法启动的问题
  3. linux s g文本替换问题
  4. 【正一专栏】希望才是深深让人绝望的东西-论国足
  5. 机器学习知识点(二十五)Java实现隐马尔科夫模型HMM之jahmm库
  6. GCN代码超详解析Two-stream adaptive graph convolutional network for Skeleton-Based Action Recognition(三)
  7. 函数返回引用什么意思_【20200917】编程入门第七课,函数(function)
  8. 从hotspot底层对象结构理解锁膨胀升级过程||深入jdk源码理解longadder的分段cas优化机制——分段CAS优化
  9. 用python openpyxl合并多个excel文件
  10. Python+selenium 自动化高级应用篇:借助pyautogui实现web前端带轨迹拖拽功能,解决ActionChains拖拽失效问题