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

ASP.NET
不同映射模式下的直线输出的效果问题
ASP.NET开发下的MVC设计模式的实现
ASP.NET编写应用程序的十大技巧
ASP.NET中使用AJAX的简单方法
ASP.NET MVC实现自己的视图引擎
认识asp.net会话状态
ASP.NET实现页面传值的几种方法
.NET中容易混淆的几组重要概念
详解.NET中的动态编译技术
如何使用ASP.Net加密Cookie
ASP.NET 2.0跨网页提交的三种方法
ASP.NET 2.0创建母版页引来的麻烦
.Net整合其他平台的一些探讨
ASP.NET编程经验技巧10则
最佳实践 ADO.NET实用经验无保留曝光
在.NET上执行多线程操作要考虑的两大因素
.Net开发 细说Visual Basic.Net
ASP.NET网络编程中经常用到的27个函数集
ASP.NET防止用户多次登录的方法
对ASP.NET MVC项目中的视图做单元测试

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


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 71 ::
收藏到网摘: 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;

 

待续!