概要
本文主要是帮助读者搞清楚什么是表达式目录树,表达书目录树能做什么,如何创建表达式目录树。后续几篇文章侧重于表达式目录树的具体应用。
表达式目录树是什么
表达式目录树是一种树型结构,它将代码以数据的形式来存储在树的各个节点中,树型结构的每个节点都是一个表达式。
这句话初听很抽象,举个例子。相信大家都使用过ADO.NET中的SqlCommand类,把拼装好的SQL代码作为参数实例化该类,SQL代码就能执行。
事实上,这种方式采用了和表达式目录树同样的设计思想。只不过SQL代码是以字符串的形式存储。这种设计思想带来的好处是我们可以传入任何需要的SQL代码,SqlCommand类的实例都可以去执行,代码具有极强的扩展性。
同样按此设计思想,对于表达式目录树,我们可以根据需要传入任何表达式去执行,以提高代码的可扩展性。
表达式目录树能做什么
根据表达式目录树的定义,我们也就不难看出,表达式目录树可以帮助我们构建任何需要的表达式,然后应用于各种复杂的查询场景。
例如对于EF的查询,我们常常碰到的需求是通过传入的URL,自动解析出查询表达式,进行查询,例如下面的例子
URL | 查询表达式 |
---|---|
https://xxxxx/students/1 | student => student.Id == 1 |
https://xxxxx/students?Name =Jack | student => student.Name == “Jack” |
https://xxxxx/students?Sex =1&Name=‘Lily | student => student.Sex== 1 && student.Name == “Lily” |
https://xxxxx/students?Department=15 | student => student.Department== 15 |
Student类可能有几十个甚至更多的栏位需要支持查询,用户的查询需求又多种多样,各种查询的排列组合可能有上百种,无法像上表那样一一枚举,只能通过URL去动态构建查询表达式。这个时候表达式目录树的优势就发挥出来了。
表达式目录树如何创建
C#中的Expression类提供的一组静态方法的创建表达式目录树,我们以构建查询表达式目录树student => student.Name.StartsWith(“Jack”)为例子,介绍常用的类:
类名 | 作用 |
---|---|
ParameterExpression | 构建表达式目录树中的变量,本例即为 => 左侧的student变量 |
MethodCallExpression | 构建表式目录树中的方法调用相关的代码,本例中的StartsWith方法调用表达式就要通过该类创建 |
MemberExpression | 构建表达式目录树中的访问类成员的代码,对应本例中的 student.Name |
LambdaExpression | 根据构建出的变量和具体的业务表达式,构建Lambda表达式 |
表达式目录树中代码的执行
表达式目录树在生成后,经过以下三步,即可执行其存储的代码:
- 调用Expression.Lambda方法,将生成的目录树student.Name.StartsWith(“Jack”)代码和变量student拼装在一起,生成LambadExpression类的对象
- 调用LambadExpression类的Compile()方法,生成委托System.Delegate类型。
- 执行用该类型的Invoke方法,执行表达式目录树中存储的代码student.Name.StartsWith(“Jack”),Invoke方法接收一个Student类型的参数。