什么是表达式树
来自微软官方文档的定义:
表达式树以树形数据结构表示代码。
它能干什么呢?
你可以对表达式树中的代码进行编辑和运算。 这样能够动态修改可执行代码、在不同数据库中执行 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 = expression.lambda >(result, a, b, c, d); var com = func.compile(); console.writeline("表达式" func); console.writeline(com(12, 12, 13, 13)); console.readkey();
上面关于表达式树的代码很多,以下这一步叫生成/创建表达式树。
expression> func = expression.lambda >(result, a, b, c, d);
以下这句叫执行表达式树
var com = func.compile();
其它代码是用于生成表达式树结点/逻辑。
回归正题,创建表达式树的两种方法。
lambda 创建表达式树
上面的表达式树示例,是用于生成
( i * j ) ( x * y )
但是就这么简单的操作,要写这么长,实在不合理。
而通过 lambda ,可以这样写
expression> func = (i, j, x, y) => (i * j) (x * y);
如果使用 lambda 生成表达式树, lambda 只能使用单行语句,不能使用 if、for等语句。
具体关于 lambda 的表达式树,后面其它文章有说明。
通过 api 创建表达式树
就是这样
expression> func = expression.lambda >(result, a, b, c, d);
两种方式左边的都是一样的,区别在于等号右边。
expression< tdelegate >
上面示例的最终结果都是生成
expression> func
func 是表达式树变量。
我们可以了解以下表达式树具有的方法和属性。
用于生成表达式树结点的,是 expression 类型。
那么,创建的表达式树 func ,是 expression
类型。
定义如下
public sealed class expression: lambdaexpression
具有方法如下
方法 | 说明 |
---|---|
compile() | 将表达式树描述的 lambda 表达式编译为可执行代码,并生成表示 lambda 表达式的委托。 |
compile(boolean) | 将表达式树描述的 lambda 表达式编译为已解释或已编译的代码,并生成表示该 lambda 表达式的委托。 |
compile(debuginfogenerator) | 将 lambda 编译到方法定义中。 (inherited from lambdaexpression) |
update(expression, ienumerable) | 创建一个与此表达式类似的新表达式,但使用所提供的子级。 如果所有子级都相同,则将返回此表达式。 |
accept(expressionvisitor) | 调度到此节点类型的特定 visit 方法。 例如,methodcallexpression调用 visitmethodcall。 |
由于 expression
继承了 lambdaexpression
,所以有很多属性方法也可以用。
body | 获取 lambda 表达式的主体。 |
---|---|
canreduce | 指示可将节点简化为更简单的节点。 如果返回 true,则可以调用 reduce() 以生成简化形式。 |
name | 获取 lambda 表达式的名称。 |
nodetype | 返回此 expression 的节点类型。 |
parameters | 获取 lambda 表达式的参数。 |
returntype | 获取 lambda 表达式的返回类型。 |
tailcall | 获取一个值,该值指示是否将通过尾调用优化来编译 lambda 表达式。 |
type | 获取此 expression 表示的表达式的静态类型。 |
好了,以上权当小笔记,备忘,目前先用不上,后面慢慢来使用。
解析/执行表达式树
创建表达式树后,就要执行表达式树。
在此之前,你需要了解 委托 delegate,func,action,以及他们中间的关系。
执行表达式树是这样子的
expression> func = expression.lambda >(result, a, b, c, d); var com = func.compile(); var runrasult = com(12, 12, 13, 13);
func 只是一个表达式树,我们把表达式树构建好后,“要将表达式树转为代码”,使用
.compile()
方法,可以将表达式树生成一个 委托(例如上面的 com)。
为了简洁上面使用了 var,实际上是这样的
funccom = func.compile();
四个参数,一个返回值。
var runrasult = com(12, 12, 13, 13);
c#里有语法糖,对委托可以这样写
expression> func = expression.lambda >(result, a, b, c, d); int runrasult = func.compile()(12, 12, 13, 13);
以后后面都是这样写了,能够缩成一行的代码,就没必要写出两行。
在 vs 里面调试和查看表达式树,可以看这里
到此这篇关于c#表达式树基础教程的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持。