程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> LINQ學習筆記:表達式樹

LINQ學習筆記:表達式樹

編輯:關於.NET

構建查詢表達式

本節中, 我們假設我們擁有一個這樣的實體類:

   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;

 

待續!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved