当前位置: 首页 > 图文教程 > 网络编程 > ASP.NET > LINQ学习笔记:表达式树

ASP.NET
asp.net Server.MapPath方法注意事项
asp.net下常用的加密算法MD5、SHA-1应用代码
几个 ASP.NET 小技巧
ASP.NET内置对象之Application对象
ASP.NET使用正则表达式屏蔽垃圾信息
asp.net“服务器应用程序不可用” 解决方法
asp.net Linq把数据导出到Excel的代码
asp.net ext treepanel 动态加载XML的实现方法
silverlight2.0Beta版TextBox输入中文解决方法
asp.net转出json格式客户端显示时间
asp.net下Linq To Sql注意事项小结
ASP.NET动态加载用户控件的实现方法
asp.net web大文件上传带进度条实例代码
asp.net DZ论坛中根据IP地址取得所在地的代码
向asp.Net进发 数据库连接操作
.net 上传文件前所未有的简单
asp.net gridview代码绑定
asp.net中List的使用方法
Asp.net(C#)实现验证码功能代码
asp.NET开发中正则表达式中BUG分析

ASP.NET 中的 LINQ学习笔记:表达式树


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 274 ::
收藏到网摘: n/a

构建查询表达式

本节中, 我们假设我们拥有一个这样的实体类:

 1: [Table] public partial class Product
 2:  
 3: {
 4:  
 5: [Column(IsPrimaryKey=true)] public int ID;
 6:  
 7: [Column] public string Description;
 8:  
 9: [Column] public bool Discontinued;
 10:  
 11: [Column] public DateTime LastSale;
 12:  
 13: }

 

委托 VS 表达式树

让我们回忆一下:

1. 本地查询,使用的Enumerable操作符,使用委托

2. 解释查询(Interpreted Query),使用Queryable操作符,使用表达式树

我们可以比较一下Where操作符在Enumerable和Queryable当中的签名:

 1: public static IEnumerable Where (this
 2:  
 3: IEnumerable source,
 4:  
 5: Funcbool> predicate)
 6:  
 7: public static IQueryable Where (this
 8:  
 9: IQueryable source,
 10:  
 11: Expressionbool>> predicate)

 

当把他们嵌入到一个查询当中的时候,Lamdba表达式看上去都是一样的,无论它是绑定到Enumerable或者Queryable:

 1: IEnumerable q1 = localProducts.Where
 2:  
 3: (p => !p.Discontinued);
 4:  
 5: IQueryable q2 = sqlProducts.Where
 6:  
 7: (p => !p.Discontinued);

 

当你将一个Lambda表达式赋给一个中间变量的时候, 你必须显示地指示是将它绑定到委托(Func<>)或者是表达式树(Expression<>>)

编译表达式树

通过调用Compile我们可以将一个表达式树转换为委托. 当我们编写的方法返回可重用的表达式时这回带来特别的价值. 为了演示,我们将给Product类增加一个静态方法, 其返回一个bool值用于断言那些Discontinued并且在过去30天内销售的产品.

 1: public partial class Product
 2:  
 3: {
 4:  
 5: public static Expressionbool>>
 6:  
 7: IsSelling()
 8:  
 9: {
 10:  
 11: return p => !p.Discontinued &&
 12:  
 13: p.LastSale > DateTime.Now.AddDays (-30);
 14:  
 15: }
 16:  
 17: }

 

(注:对于类似的扩展方法,我们应该编写一个全新的文件从而避免去覆盖由VS的设计器自动产生的文件.)

此方法可以同时被用于本地查询和解释查询,如下所示:

 1: void Test( )
 2:  
 3: {
 4:  
 5: var dataContext = new MyTypedDataContext (“connectionString”);
 6:  
 7: Product[] localProducts =
 8:  
 9: dataContext.Products.ToArray( );
 10:  
 11: IQueryable sqlQuery =
 12:  
 13: dataContext.Products.Where(Product.IsSelling());
 14:  
 15: IEnumerable localQuery =
 16:  
 17: localProducts.Where(Product.IsSelling.Compile());
 18:  
 19: }

 

相比之下, 我们并不能将一个委托转换为表达式树,这也使得表达式树更加有用.

AsQueryable

使用AsQueryable操作符可以编写用于操作本地或者远程序列的查询:

 1: IQueryable FilterSortProducts
 2:  
 3: (IQueryable input)
 4:  
 5: {
 6:  
 7: return from p in input
 8:  
 9: where
 10:  
 11: order by …
 12:  
 13: select p;
 14:  
 15: }
 16:  
 17: void Test()
 18:  
 19: {
 20:  
 21: var dataContext = new MyTypedDataContext (“connectionString”);
 22:  
 23: Product[]localProducts =
 24:  
 25: dataContext.Products.ToArray();
 26:  
 27: var sqlQuery =
 28:  
 29: FilterSortProducts (dataContext.Products);
 30:  
 31: var localQuery =
 32:  
 33: FilterSortProducts (localProducts.AsQueryable());
 34:  
 35: }

 

AsQueryable对本地查询包装了一层Queryable<>外衣,这使得接下来的子查询都是针对表达式树的.当你开始枚举结果集的时候,表达式树会被隐式编译转换成为本地查询然后向往常一直执行.

表达式树

我们之前说过将一个Lambda表达式赋值给一个Expression类型变量会引起C#编译器解析表达式树.使用编程手段, 我们可以在运行时做相同的事情-换句话说, 从零开始动态创建表达式树. 结果集可以被转换为Expression并被使用于LINQ to SQL查询中,或者通过调用Compile将其转换为委托.

表达式DOM

一个表达式树是一个小型DOM. 每一个节点表示一个System.Linq.Expressions命名空间下的一个类型. 其基类是Expression(非泛型),而泛型Expression实际上是表示类型化的Lambda表达式.

Expression<>的基类是非泛型的LambdaExpression类, LambdaExpression提供了针对Labmbda表达式树的统一类型:任何Expression<>都看可以被转换为LambdaExpression.

为了创建表达式树, 我们并不需要直接实例化节点类,而是通过调用Expression类提供的静态方法:

 1: //创建输入参数s
 2: ParameterExpression p = Expression.Parameter(typeof(string), “s”);
 3: //参数属性Length
 4: MemberExpression stringLength = Expression.Property(p, “Length”);
 5: //常量5
 6: ConstantExpression five = Expression.Constant(5);
 7: //比较操作符
 8: BinaryExpression comparison = Expression.LessThan(stringLength, five);
 9: Expression<string,bool>> lambda = Expression.Lambda<string,bool>>(comparison,p);
 10: //转换为委托
 11: Func<string, bool> runnable = lambda.Compile();
 12: Console.WriteLine(runnable(“James”)); //False
 13: Console.WriteLine(runnable(“dog”)); //True

 

此示例动态创建了一个如下的Lambda表达式:

 1: Expression<string, bool>> f = s => s.Length < 5;

 

待续!