Linq系列(5)——表达式树之案例应用
在进入今天的正题之前,先感慨下本人的blog的人气一篇不如一篇。再加上换公司后人身自由受到了比之前大得多得多的限制,实在令本人有些郁闷。不过每次提笔写些东西跟大家分享,总是能让我感到愉悦和欣慰,希望我的文章和理解能帮助到大家。前段时间周星星给我聊天的时候跟我说我写的东西msdn上都能查到,希望我能多写写自己的思考。其实是这样的,就知识查询手册这个层面来说,我相信.net的知识msdn上没有查不到的,我只是努力给大家展现我自己的一个理解和学习的过程,把一些知识以一个特定的逻辑顺序串联起来,希望通过我的一些带有个人色彩的陈述和表达使大家能理解和运用这些知识。
好了,进入正题,上一篇已经说过了,这一篇会写一些轻松的东西,主要来写写表达式树的一些案例和应用,相对而言会比较简单。
我之前已经写过,方法可以做什么表达式树就可以做什么。我们先来看一个例子。
有一个Aircraft的类
public class Aircraft
{
public int[] AircraftNumber
{
get;
set;
} public string AirlineId
{
get;
set;
} public Aircraft()
{
} public bool Test()
{
return true;
}
}
首先 我们来看一个函数,这个函数的作用就是判断Aircraft中的AirlineId是否为null,我们先来看看用lambda表达式怎么写
Func<Aircraft, bool> methodEqualNull = item => item.AirlineId == null;
好,现在问题来了。如果我们需要在运行时来构建这个逻辑怎么办,具体一点,比如我们需要把这个AirlineId当成参数传进来,就是运行时判断哪个属性是否为null怎么办,然后甚至null也是运行时动态传进来的怎么办,即,我们需要运行时判断某个属性是否等于某个具体常量,怎么办。
这个时候我们就可以用表达式树了。
ParameterExpression aircraftParameter = Expression.Parameter(typeof(Aircraft), "aircraftTestString");
MemberExpression memberAirlineIdExpression = Expression.Property(aircraftParameter, "AirlineId");
ConstantExpression nullConstant = Expression.Constant(null);
Expression<Func<Aircraft, bool>> equalNull = Expression.Lambda<Func<Aircraft, bool>>
(Expression.Equal (memberAirlineIdExp ression, nullConstant),
new ParameterExpression[] { aircraftParameter }
);
我们先来普及下表达式树中几个常用的类:
ParameterExpression:参数表达式,用于表示表达式树中需要用到的参数
MemberExpression:成员表达式,用于表示某个ParameterExpression中的某个成员
好,知道了这2个概念,我们就来分析下这2句话:
ParameterExpression aircraftParameter = Expression.Parameter(typeof(Aircraft), "aircraftTestString");
这一句表示表达式树中有一个参数,它的类型是Aircraft,
MemberExpression memberAirlineIdExpression = Expression.Property(aircraftParameter, "AirlineId");
这一句表示有一个memberAirlineIdExpression ,这个变量用来表示Aircraft这个类型中的AirlineId这个属性
ConstantExpression:这个简单,就是常量表达式
Expression.Lambda<Func<Aircraft, bool>>
(Expression.Equal(memberAirlineIdExpression, nullConstant),
new ParameterExpression[] { aircraftParameter }
);
这句代码很重要,我们具体分析下,首先它表示构建一个参数为Aircraft,返回类型为bool的表达式树,
new ParameterExpression[] { aircraftParameter },这句话表示这个表达式树的参数为aircraftParameter ,
Expression.Equal(memberAirlineIdExpression, nullConstant)这句话表示这个表达式的逻辑是判断memberAirlineIdExpression和nullConstant是否相等。
好了,有了上面的例子,我们再来看一个类似的表达式树,它要构建出item => item.AirlineId == string.Empty这个逻辑
ConstantExpression emptyConstant = Expression.Constant(string.Empty);
Expression<Func<Aircraft, bool>> equalEmpty = Expression.Lambda<Func<Aircraft, bool>>
(
Expression.Equal(memberAirlineIdExpression, emptyConstant),
new ParameterExpression[] { aircraftParameter }
);
好了,通过上面两个例子,我们可以看出,如果运用表达式树,ParameterExpression,MemberExpression,都可以在运行时当成参数传入,也都可以在运行时动态构建,甚至如果大家自己尝试,大家可以发现,Expression.Equal这个很核心的逻辑,我们都可以通过传入一个字符串,然后调用Expression.Call方法来构建,但我在此不推荐这么做,因为字符串没有编译时的检查,很不完全,就算是一个没有对应具体方法的字符串也可以被传入。
然后,已经构建好的表达式树也可以被其他的表达式树调用,我们再来看个例子
Expression<Func<Aircraft, bool>> expressionString = Expression.Lambda<Func<Aircraft, bool>>
(
Expression.Or(equalNull.Body, equalEmpty.Body),
new ParameterExpression[] { aircraftParameter }
);
这段代码就是运用之前的2个表达式树,构建了一个string.IsNullOrEmpty的逻辑。
顺带说一下,Body和Parameter是表达式树中2个很核心的概念,我会在下一篇博文中具体来说。
好,我曾经说过,方法可以做的事情表达式树都可以做,因为实际上方法可以按照表达式树的形式来进行保存。
大家可以参考下这篇文章http://rednaxelafx.javaeye.com/blog/247270
我作一些摘抄
算术表达式部分:
static void Add( ) {
// Expression<Func<int, int, int>> add = ( x, y ) => x + y;
ParameterExpression x = Expression.Parameter( typeof( int ), "x" );
ParameterExpression y = Expression.Parameter( typeof( int ), "y" );
Expression<Func<int, int, int>> add = Expression.Lambda<Func<int, int, int>>(
Expression.Add(
x, // left
y // right
),
new ParameterExpression[ ] { x, y }
);
}
按位运算表达式
// "<<" operator
static void LeftShift( ) {
// Expression<Func<int, int, int>> lshift = ( x, y ) => x << y;
ParameterExpression x = Expression.Parameter( typeof( int ), "x" );
ParameterExpression y = Expression.Parameter( typeof( int ), "y" );
Expression<Func<int, int, int>> lshift = Expression.Lambda<Func<int, int, int>>(
Expression.LeftShift(
x, // left
y // right
),
new ParameterExpression[ ] { x, y }
);
}
条件表达式
// "? :" operator
static void Condition( ) {
// Expression<Func<bool, int, int, int>> cond = ( c, x, y ) => c ? x : y;
ParameterExpression c = Expression.Parameter( typeof( bool ), "c" );
ParameterExpression x = Expression.Parameter( typeof( int ), "x" );
ParameterExpression y = Expression.Parameter( typeof( int ), "y" );
Expression<Func<bool, int, int, int>> cond = Expression.Lambda<Func<bool, int, int, int>>(
Expression.Condition(
c, // test
x, // if true
y // if false
),
new ParameterExpression[ ] { c, x, y }
);
}
等于大于小于等比较大小的部分
static void GreaterThan( ) {
// Expression<Func<int, int, bool>> gt = ( x, y ) => x > y;
ParameterExpression x = Expression.Parameter( typeof( int ), "x" );
ParameterExpression y = Expression.Parameter( typeof( int ), "y" );
Expression<Func<int, int, bool>> gt = Expression.Lambda<Func<int, int, bool>>(
Expression.GreaterThan(
x, // left
y // right
),
new ParameterExpression[ ] { x, y }
);
}
关系表达式
static void AndAlso( ) {
// Note that And() is for bitwise and, and AndAlso() is for logical and.
// Note also that the shortcut semantics is implemented with AndAlso().
// Expression<Func<bool, bool, bool>> and = ( x, y ) => x && y;
ParameterExpression x = Expression.Parameter( typeof( bool ), "x" );
ParameterExpression y = Expression.Parameter( typeof( bool ), "y" );
Expression<Func<bool, bool, bool>> and = Expression.Lambda<Func<bool, bool, bool>>(
Expression.AndAlso(
x, // left
y // right
),
new ParameterExpression[ ] { x, y }
);
}
类型转换表达式
// C-style conversion
static void Convert( ) {
// Expression<Func<int, short>> conv = x => ( short ) x;
ParameterExpression x = Expression.Parameter( typeof( int ), "x" );
Expression<Func<int, short>> conv = Expression.Lambda<Func<int, short>>(
Expression.Convert(
x, // expression
typeof( short ) // type
),
new ParameterExpression[ ] { x }
);
}
成员表达式
// C-style conversion
static void Convert( ) {
// Expression<Func<int, short>> conv = x => ( short ) x;
ParameterExpression x = Expression.Parameter( typeof( int ), "x" );
Expression<Func<int, short>> conv = Expression.Lambda<Func<int, short>>(
Expression.Convert(
x, // expression
typeof( short ) // type
),
new ParameterExpression[ ] { x }
);
}
数组表达式
static void ArrayIndex( ) {
// Expression<Func<int[ ], int, int>> aryIdx = ( a, i ) => a[ i ];
ParameterExpression a = Expression.Parameter( typeof( int[ ] ), "a" );
ParameterExpression i = Expression.Parameter( typeof( int ), "i" );
Expression<Func<int[ ], int, int>> aryIdx = Expression.Lambda<Func<int[ ], int, int>>(
Expression.ArrayIndex(
a, // array
i // index
),
new ParameterExpression[ ] { a, i }
);
}
方法/委托调用表达式
// Calling a static method
static void Call( ) {
// Note that to call a static method, use Expression.Call(),
// and set "instance" to null
// Expression<Func<string, int>> scall = s => int.Parse( s );
ParameterExpression s = Expression.Parameter( typeof( string ), "s" );
Expression<Func<string, int>> scall = Expression.Lambda<Func<string, int>>(
Expression.Call(
null, // instance
typeof( int ).GetMethod( // method
"Parse", new Type[ ] { typeof( string ) } ),
new Expression[ ] { s } // arguments
),
new ParameterExpression[ ] { s }
);
}
https://www.cnblogs.com/FlyEdward/archive/2010/04/15/Linq_ExpressionTree5.html
Linq系列(5)——表达式树之案例应用的更多相关文章
- Linq系列(7)——表达式树之ExpressionVisitor
大家好,由于今天项目升级,大家都在获最新代码,所以我又有时间在这里写点东西,跟大家分享. 在上一篇的文章中我介绍了一个dll,使大家在debug的时候可以可视化的看到ExpressionTree的Bo ...
- LINQ to Objects系列(4)表达式树
为了进一步加深对Lambda表达式的理解,我们需要掌握一个新的知识,Lambda表达式树,可能听名字看起来很高深和难以理解,但实际上理解起来并没有想象中那么难,这篇文章我想分以下几点进行总结. 1,表 ...
- LINQ Expresstion Tree 表达式树
Expression trees represent code in a tree-like data structure, where each node is an expression, for ...
- C#动态构建表达式树(三)——表达式的组合
C#动态构建表达式树(三)--表达式的组合 前言 在筛选数据的过程中,可能会有这样的情况:有一些查询条件是公共的,但是根据具体的传入参数可能需要再额外增加一个条件.对于这种问题一般有两种方法: a. ...
- C# - LINQ 表达式树
表达式树(Expression Tree) 表达式树是不可执行的代码,它只是用于表示一种树状的数据结构,树上的每一个节点都表示为某种表达式类型,大概有25种表达式类型,它们都派生自Expression ...
- 追根溯源之Linq与表达式树
一.什么是表达式树? 首先来看下官方定义(以下摘录自巨硬官方文档) 表达式树表示树状数据结构中的代码,其中每个节点都是表达式,例如,方法调用或诸如的二进制操作x < y. 您可以编译 ...
- [.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门
[.net 面向对象程序设计进阶] (6) Lamda表达式(二) 表达式树快速入门 本节导读: 认识表达式树(Expression Tree),学习使用Lambda创建表达式树,解析表达式树. 学习 ...
- Lambda表达式和Lambda表达式树
LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态. 为了富有效率的使用数据库和其他查询引擎,我们需要一种不同的方式表示管道中的各个操作.即把代码当作可在编程中进行检查的数据. Lambd ...
- 转载:C#特性-表达式树
原文地址:http://www.cnblogs.com/tianfan/ 表达式树基础 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希望大家看到它其实并不像想象中那么难.您只要有普通 ...
随机推荐
- Python 小程序,对文件操作及其它
以下是自己写的几个对文件操作的小程序,里面涉及到文件操作,列表(集合,字典)的运用等.比方说,从文件里读取一行数据.分别存放于列表中,再对列表进行操作.如去掉里面的反复项.排序等操作. 常见对文件里行 ...
- lucene 学习一
索引工具的三部分 1.索引部分 2.分词部分 3.搜索部分 查看索引的工具:luke java -jar fileName.jar 目标:为文件夹的所有的文档生成索引并搜索它 package co ...
- Tomcat中配置MySQL数据库连接池
Web开发中与数据库的连接是必不可少的,而数据库连接池技术很好的优化了动态页与数据库的连接,相比单个连接数据库连接池节省了很大的资源.用一个通俗的比喻:如果一个人洗澡需花一桶水,那一百个人就要花一百桶 ...
- Ubuntu下开启root登陆--并开启SSH登录验证
Ubuntu下开启root登陆亲手安装过Ubuntu的童鞋都知道,默认安装只会添加一个普通用户名和密码,而超级用户权限则是利用sudo命令来执行.在Ubuntu下使用root登陆或者在shell中用s ...
- Git 修改用户名以及提交邮箱
问题背景: 在已毕业师兄的电脑上提交自己的 Github 代码,(尽管有重新设置了 自己的SSH),但是 Github网站提交结果却显示师兄提交的: 验证当前本地属性: 怎么知道本地有设置?git c ...
- GitHub上最火的Android开源项目(完结篇)
摘要:截至目前,在GitHub“最受欢迎的开源项目”系列文章中我们已介绍了40个Android开源项目,对于如此众多的项目,你是Mark.和码友分享经验还是慨叹“活到老要学到老”?今天我们将继续介绍另 ...
- HTML5 学习笔记 应用程序缓存
使用html5 通过创建cache manifest文件,可以轻松地创建web应用的离线版本. html5引入了应用程序缓存,这意味着web应用可进行缓存,并可在没有因特网连接时进行访问. 应用程序缓 ...
- TCP 三次握手过程详解
TCP(Transmission Control Protocol) 传输控制协议 TCP:面向连接的,可靠的,基于字节流的传输层通信协议 TCP(传输层)位于IP层(网络层)之上,应用层之下,不同的 ...
- iframe自适应高度处理
一中方法: 在子页面加载完毕的时候执行 parent.document.getElementById("iframe").height=0; parent.document.get ...
- scikit-learn:在实际项目中用到过的知识点(总结)
零.全部项目通用的: http://blog.csdn.net/mmc2015/article/details/46851245(数据集格式和预測器) http://blog.csdn.net/mmc ...