Linq之Expression高级篇(常用表达式类型)
目录
写在前面
首先回顾一下上篇文章的内容,上篇文章介绍了表达式树的解析和编译。如果忘记了,可以通过下面系列文章提供的入口进行复习。这篇文章将介绍常见的表达式类型。
常见的表达式类型都有个共同的基类Expression。创建这些类型的对象,是通过API的方式创建的(也就是Expression的静态方法),首先引入命名空间:
using System.Linq.Expressions;
系列文章
变量表达式
在表达式树中使用ParameterExpression或者ParameterExpression表达式表示变量类型,下面看一个例子,我们定义一个int类型的变量i:
// ParameterExpression表示命名的参数表达式。
ParameterExpression i = Expression.Parameter(typeof(int),"i");
或者使用
ParameterExpression j = Expression.Variable(typeof(int), "j");
通过f12转到定义,发现这两个方法的注释几乎是一样的。静态方法Parameter第一个参数:定义的参数类型,第二个参数:为参数名称。
常量表达式
在表达式树中使用ConstantExpression表达式表示具有常量值的表达式。,看一个例子,我们定义一个int类型的常量5.并将该值赋值给上面定义的变量i
// ParameterExpression表示命名的参数表达式。
ParameterExpression i = Expression.Parameter(typeof(int), "i");
//ParameterExpression j = Expression.Variable(typeof(int), "j");
ConstantExpression constExpr = Expression.Constant(, typeof(int));
// 创建一个表示赋值运算的 System.Linq.Expressions.BinaryExpression
//表示包含二元运算符的表达式。
BinaryExpression binaryExpression = Expression.Assign(i, constExpr);
Constrant方法第一个参数:常量,第二个参数为什么类型的常量。
这里提到了BinaryExpression表达式,该表达式标识包含二元运算符的表达式,类似与=,>这样的二元表达式都可以使用BinaryExpression表达式来表示。
调试模式下,在自动窗口查看当前表达式的DebugView属性,这个属性在调试表达式树的时候是非常有用的:
变量:

常量:

二元表达式:

通过观察上面的图,可知变量调试模式下DebugView属性将显示前面带有“$”符号的 ParameterExpression 变量名称。那么如果参数没有名称,则会为其分配一个自动生成的名称,例如 $var1 或 $var2(这里不再举例)。
条件表达式
在很多时候,我们都需要使用条件表达式来过滤一些数据,然后返回满足条件的数据,在表达式中有这样一些表达式满足你的需求。
常见运算符
>,>=

<,<=

if....then:如果满足条件那么..
if...then...else:如果满足条件执行某某代码,否则执行另外的逻辑

一个例子
IfThenElse方法
public static ConditionalExpression IfThenElse(
Expression test,
Expression ifTrue,
Expression ifFalse
)
bool test = true;
ConditionalExpression codition = Expression.IfThenElse(
//条件
Expression.Constant(test),
//如果条件为true,调用WriteLine方法输出“条件为true”
Expression.Call(
null,
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
Expression.Constant("条件为true")
),
//如果条件false
Expression.Call(
null,
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
Expression.Constant("条件为false")
)
);
//编译表达式树,输出结果
Expression.Lambda<Action>(codition).Compile()();
输出结果

例子描述:条件test包装为常量表达式,因为test为true,所以执行iftrue的表达式,并调用WriteLine方法打印出信息。
赋值表达式
=
还以上面为变量i赋值的例子为例
ParameterExpression i = Expression.Parameter(typeof(int), "i");
//ParameterExpression j = Expression.Variable(typeof(int), "j");
ConstantExpression constExpr = Expression.Constant(, typeof(int));
// 创建一个表示赋值运算的 System.Linq.Expressions.BinaryExpression
//表示包含二元运算符的表达式。
BinaryExpression binaryExpression = Expression.Assign(i, constExpr);
+=
BinaryExpression b2 = Expression.AddAssign(i, constExpr);
-=
BinaryExpression b3 = Expression.SubtractAssign(i, constExpr);
*=
BinaryExpression b4 = Expression.MultiplyAssign(i, constExpr);
/=
BinaryExpression b5= Expression.DivideAssign(i, constExpr);
举一个例子
ParameterExpression i = Expression.Parameter(typeof(int), "i");
BlockExpression block = Expression.Block(
new[] { i },
//赋初值 i=5
Expression.Assign(i, Expression.Constant(, typeof(int))),
//i+=5 10
Expression.AddAssign(i, Expression.Constant(, typeof(int))),
//i-=5 5
Expression.SubtractAssign(i, Expression.Constant(, typeof(int))),
//i*=5 25
Expression.MultiplyAssign(i, Expression.Constant(, typeof(int))),
//i/=5 5
Expression.DivideAssign(i, Expression.Constant(, typeof(int)))
);
Console.WriteLine(Expression.Lambda<Func<int>>(block).Compile()());
结果

二元运算符表达式
在上面也提到了部分二元运算符表达式,类似加减乘除这样的运算符,对于二元运算符,就不再举例。这些返回的表达式树,都可以使用BinaryExpression来接收,或者使用基类Expression接收,或者更省事,使用var关键字。
一元运算符表达式
类似++,--运算符
i++等价于i=i+1,运算顺序就是i先加1,然后再赋值给i。在表达式书中使用Expression的PostIncrementAssign方法来进行自增或者自减操作。返回结果为UnaryExpression类型,同样可以使用基类Expression接收,或者var。
循环表达式
在表达式树中使用Expression的Loop方法实现循环。
块表达式
在前面的文章中,也说了不能使用Lambda方式创建带块级的表达式树,不然会有如下的错误

通过API的方式可以创建块级表达式树,其中Expression的Block方法功不可没。例如上面的加减乘除的例子中,可以包括多个Expression。
那么,下面就举一个包含自增的一元表达式,循环的表达式块,并输出结果。
输出1-100之间的所有偶数。
class Program
{
static void Main(string[] args)
{
//变量i
ParameterExpression i = Expression.Parameter(typeof(int), "i");
//跳出循环
LabelTarget label = Expression.Label();
BlockExpression block = Expression.Block(
new[] { i },
//为i赋初值
Expression.Assign(i, Expression.Constant(, typeof(int))),
Expression.Loop(
Expression.IfThenElse(
//如果i<=100
Expression.LessThanOrEqual(i, Expression.Constant(, typeof(int))),
//如果为true.进入循环体
Expression.Block(
Expression.IfThen(
//条件i%2==0;
Expression.Equal(Expression.Modulo(i, Expression.Constant(, typeof(int))),
Expression.Constant(, typeof(int))),
Expression.Call(typeof(Console).GetMethod("WriteLine",
new Type[] { typeof(int) }), new[] { i })),
//i++
Expression.PostIncrementAssign(i)
),
//如果i>100
Expression.Break(label)),
label
));
Expression.Lambda<Action>(block).Compile()();
Console.Read();
}
}
结果

总结
本篇文章介绍了几种常见的表达式类型,当然,还有很多并没有列出,比如switch case,try catch等。如果在项目中需要创建复杂的表达式树,Expression的静态方法Block是必不可少的。希望通过本篇的学习,对你了解Expression有所帮助。
参考文章
https://msdn.microsoft.com/zh-cn/library/dd323961(v=vs.110).aspx
https://msdn.microsoft.com/zh-cn/library/bb397951.aspx
Linq之Expression高级篇(常用表达式类型)的更多相关文章
- fabricjs 高级篇(自定义类型)
原文:https://www.sitepoint.com/fabric-js-advanced/ <html> <head> <script src='./js/fabr ...
- 【.net深呼吸】动态类型(高级篇)
前面老周给大家介绍了动态类型使用的娱乐级别用法,其实,在很多情景下,娱乐级别的用法已经满足需求了. 如果,你想自己来控制动态类型的行为和数据的存取,那么,就可以考虑用今天所说的高大上技术了.比如,你希 ...
- Kotlin——从无到有系列之高级篇(一):Lambda表达式
如果您对Kotlin很有兴趣,或者很想学好这门语言,可以关注我的掘金,或者进入我的QQ群大家一起学习.进步. 欢迎各位大佬进群共同研究.探索 QQ群号:497071402 进入正题 经过前面一系列对K ...
- Kotlin——高级篇(五):集合之常用操作符汇总
在上一篇文章Kotlin--高级篇(四):集合(Array.List.Set.Map)基础中讲解到了数组Array<T>.集合(List.Set.Map)的定义与初始化.但是由于篇幅的原因 ...
- ORM查询语言(OQL)简介--高级篇:脱胎换骨
相关文章内容索引: ORM查询语言(OQL)简介--概念篇 ORM查询语言(OQL)简介--实例篇 ORM查询语言(OQL)简介--高级篇:脱胎换骨 ORM查询语言(OQL)简介--高级篇(续):庐山 ...
- Linq之Expression初见
目录 写在前面 系列文章 Expression 表达式树创建方式 一个例子 总结 写在前面 上篇文章介绍了扩展方法,这篇文章开始将陆续介绍在linq中使用最多的表达式树的相关概念,以概念及例子一一列出 ...
- ORM查询语言(OQL)简介高级篇
ORM查询语言(OQL)简介--高级篇:脱胎换骨 在写本文之前,一直在想文章的标题应怎么取.在写了<ORM查询语言(OQL)简介--概念篇>.<ORM查询语言(OQL)简介--实例篇 ...
- Linux运维入门到高级全套常用要点
Linux运维入门到高级全套常用要点 目 录 1. Linux 入门篇................................................................. ...
- ORM查询语言(OQL)简介--高级篇(续):庐山真貌
相关文章内容索引: ORM查询语言(OQL)简介--概念篇 ORM查询语言(OQL)简介--实例篇 ORM查询语言(OQL)简介--高级篇:脱胎换骨 ORM查询语言(OQL)简介--高级篇(续):庐山 ...
随机推荐
- EXCEL IF 函数 模糊查询
A列都是产品名,比如衬衫,长袖衬衫,短袖衬衫,短裙,长裙 搜索A列的产品名,凡是含有“衬衫”的一律在B列对应行输出“衬衫”,凡是含有“裙”字的一律输出“裙子”在B列对应行,请教一下怎么写函数,本来用I ...
- SSIS hang with unhandle exception
如果你的packages在执行的过程中有没有被捕获到的异常,则sqldumper会跳出来获取这些异常信息输出,存在下面的目录中: C:\Program Files\Microsoft SQL Serv ...
- 为Secure Store Service生成新密钥,解决“生成密钥过程中发现错误”的问题
我们集成TFS和SharePoint Server以后,一个最常见的需求是通过SharePoint Server的Excel Service读取TFS报表中的信息,利用Excel Service的强大 ...
- SDRAM总结
使用的流程 W9825G6JH winbond sdram 4M words X 4banks X 16bits=. Accesses to the SDRAM are burst oriented. ...
- EventBus (三) 源码解析 带你深入理解EventBus
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40920453,本文出自:[张鸿洋的博客] 上一篇带大家初步了解了EventBus ...
- Android Studio系列教程六--Gradle多渠道打包
Android Studio系列教程六--Gradle多渠道打包 2015 年 01 月 15 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://stormzh ...
- localStorage实现购物车数量单价和总价实时同步(二)
利用localStorage实时显示购物车小计和总价页面显示: 和昨天的原理相同,本地存储同时实时循环计算总价之和,注意循环时候的先清空再计算 Success is getting what you ...
- 当文本溢出包含的元素时加省略号之text-overflow
text-overflow是css3的属性,用来处理文本溢出,默认裁剪处理,text-overflow属性只能用于block和inline-block元素,内联的和box,flex-flow:colu ...
- VFS分析(一)挂载(持续更新)
基础知识在<深入linux内核架构>第8章,自行脑补. 看下几个关键的过程: do_add_mount里有重要函数lock_mount, lock_mount函数的输入是struct pa ...
- discuz编码转换UTF8与GBK互转完美适合Discuz3.x系列
由于一些网站通信编码的问题不得不把一直使用的网站编码由UTF8转为GBK,在转换过程中在官方看了很多方法,自己也都尝试了一些最后都没有能够成功,数据库的转换一直都是没有大问题,不存在丢失什么的,能看到 ...