时间:2021-05-20
表达式树使用一种类似树的结构来表示代码,它的每个节点都是一个表达式,比如方法调用和x<y这样的二元运算等。我们可以对表达式树的内容进行编辑和运算,这样能够动态修改可执行代码,以及动态创建查询等。我们可以使用匿名lambda表达式或者C# API来创建表达式树。
这一系列文章,主要是对C#表达式树的一种总结,基本知识参考MSDN的内容 这部分内容可以直接到MSDN上查看,后面的几篇文章主要分享一下,在工作中碰到的应用到表达式树的部分,谨做为记录和分享。
生成表达式树
通过lambda表达式创建表达式树
可以通过将lambda表达式赋值给Expression<TDelegate>类型的变量,编译器可以自动生成创建该lambda表达式的表达式树。C#编译器只能从lambda表达式生成表达式树,只能是单行lambda表达式,不能解析多行lambda语句,如下,可以通过一下方式创建lambda表达式 num=>num<5的表达式树:
通过API创建表达式树
使用API创建表达式,需要使用Expression类,这个类包含了创建特定类型表达式树节点的静态工厂方法,比如表示参数的变量ParameterExpression,表示方法调用的MethodExpression。ParameterExpression,MethodExpression以及其他特定的表达式类型都在System.Linq.Expression命名空间里定义,这些类型都派生于Expression抽象类。
下面的例子是使用API方式创建num=>num<5的lambda表达式对应的表达式树:
ParameterExpression numPara = Expression.Parameter(typeof(int), "num");//参数numConstantExpression five = Expression.Constant(5, typeof(int));//常数5BinaryExpression numLessThanFive = Expression.LessThan(numPara, five);Expression<Func<int, bool>> lambda1 = Expression.Lambda<Func<int, bool>>(numLessThanFive, new ParameterExpression[] { numPara });从.NET Framework 4开始,表达式树API还支持赋值以及流程控制,比如循环,条件块和try ... catch块等。相对于通过lambda表达式创建表达式树,可以利用API创建更加复杂的表达式树,比如下面使用API创建数字阶乘的表达式树:
//参数valueParameterExpression value = Expression.Parameter(typeof(int), "value");//本地变量ParameterExpression result = Expression.Parameter(typeof(int), "result");//标签,用来跳出循环LabelTarget label = Expression.Label(typeof(int));//创建表达式块BlockExpression block = Expression.Block( //添加本地参数result new[] { result }, //result=1 赋值 Expression.Assign(result, Expression.Constant(1)), //循环 Expression.Loop( //循环条件 Expression.IfThenElse( //如果 value>1 Expression.GreaterThan(value, Expression.Constant(1)), //则 result*=value--; Expression.MultiplyAssign(result, Expression.PostDecrementAssign(value)), //否则跳出loop循环。跳到label的语句执行 Expression.Break(label, result) ), label ));//编译表达式树Func<int, int> factor = Expression.Lambda<Func<int, int>>(block, value).Compile();//执行,输出结果120Console.WriteLine(factor(5));解析表达式树
在获取了表达式树之后,如何获取表达式树的每一个部分,这个在有些情况下非常有用,下面这个例子展示了如何获取num=>num<5的各个部分。
Expression<Func<int, bool>> expreTree = num => num < 5;ParameterExpression param = (ParameterExpression)expreTree.Parameters[0];//numBinaryExpression operation = (BinaryExpression)expreTree.Body;//<ParameterExpression left = (ParameterExpression)operation.Left;//numConstantExpression right = (ConstantExpression)operation.Right;//5 //output Decomposed expression: num => num LessThan 5 Console.WriteLine("Decomposed expression:{0} = > {1} {2} {3}", param.Name, left.Name, operation.NodeType, right.Value);编译表达式树
Expression<TDelegate>类型有Compile方法,可以将表达式树编译成对应的TDelegate委托类型,使用方法如下:
// 创建表达式树Expression<Func<int, bool>> expr = num => num < 5;// 将表达式树编译成对应委托 Func<int, bool> result = expr.Compile();//调用委托方法,输出TrueConsole.WriteLine(result(4));//也可以直接编译后调用,输出TrueConsole.WriteLine(expr.Compile()(4));再比如,下面例子演示了,创建一个表达式树,然后编译执行:
//创建表达式树的执行逻辑BinaryExpression be = Expression.Power(Expression.Constant(2D), Expression.Constant(3D));//创建表达式树Expression<Func<double>> le = Expression.Lambda<Func<double>>(be);//编译表达式树Func<double> compileExpression = le.Compile();//执行lambda表达式,获得结果8double result = compileExpression();Console.WriteLine(result);表达式树的修改
表达式树是不可变对象(immutable),跟string类似,不能直接修改,只能复制一个然后重新构造。具体参考MSDN How to modify expression trees (C#).
结语
本篇全部内容参考MSDN上表达式树部分的内容,如果有基础建议直接看,这里只是个人作为笔记,也是表达式树的最基础部分,后文会介绍表达式树的一些用法。
以上就是C#表达式树的基本用法讲解的详细内容,更多关于C#表达式树的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文以实例形式介绍了C#中Lambda表达式的用法,分享给大家供大家参考之用。具体如下:从委托的角度来看,Lambda表达式与匿名方法没有区别。在前面C#基础之
1、表达式目录树 表达式目录树,在C#中是Expression来定义的,它是一种语法树,或者说是一种数据结构。其主要用于存储需要计算、运算的一种结构,它只提供
js中的正则表达式比起C#中的正则表达式要弱很多,但基本够用了1定义正则表达式2关于验证的三个这则表达式方法3正则表达式式的转义字符1定义正则表达式在js中定义
本文实例讲述了C#正则表达式Regex类用法,分享给大家供大家参考。具体实现方法如下:一、在C#中,要使用正则表达式类,请在源文件开头处添加以下语句:复制代码代
本文实例为大家分享了C语言实现对后缀表达式(逆波兰表达式)的求解代码,供大家参考,具体内容如下逆波兰表达式:逆波兰表达式又叫后缀表达式。它是由相应的语法树的后序