<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      趣味編程:C#中Specification模式的實現(參考答案 - 下)

      2009-09-29 10:35  Jeffrey Zhao  閱讀(12441)  評論(19)    收藏  舉報

      上一篇文章中我們利用C#語言的特性實現了一種輕量級的Specification模式,它的關鍵在于拋棄了具體的Specification類型,而是使用一個委托對象代替唯一關鍵的IsSatisfiedBy方法邏輯。據我們分析,其優勢之一在于使用簡單,其劣勢之一在于無法靜態表示。但是它們還都是在處理“業務邏輯”,如果涉及到一個用于LINQ查詢或其他地方的表達式樹,則問題就不那么簡單了——但也沒有我們想象的那么復雜。

      好,那么我們就把場景假想至LINQ上。LINQ與普通業務邏輯不同的地方在于,它不是用一個IsSatisfiedBy方法或一個委托對象用來表示判斷邏輯,而是需要構造一個表達式樹,一種數據結構。如果您還不清楚表達式樹是什么,那么可以看一下腦袋的寫的上手指南。這是.NET 3.5帶來的重要概念,在4.0中又得到了重要發展,如果您要在.NET方面前進,這是一條必經之路。

      And、Or和Not之間,最容易處理的便是Not方法,于是我們從這個地方下手,直接來看它的實現:

      public static class SpecExprExtensions
      {
          public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> one)
          {
              var candidateExpr = one.Parameters[0];
              var body = Expression.Not(one.Body);
      
              return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
          }
      }

      一個Expression<TDelegate>對象中主要有兩部分內容,一是參數,二是表達式體(Body)。對于Not方法來說,我們只要獲取它的參數表達式,再將它的Body外包一個Not表達式,便可以此構造一個新的表達式了。這部分邏輯非常簡單,看了腦袋的文章,了解了表達式樹的基本結構就能理解這里的含義。那么試驗一下:

      Expression<Func<int, bool>> f = i => i % 2 == 0;
      f = f.Not();
      
      foreach (var i in new int[] { 1, 2, 3, 4, 5, 6 }.AsQueryable().Where(f))
      {
          Console.WriteLine(i);
      }
      

      打印出來的自然是所有的奇數,即1、3、5。

      而And和Or的處理上會有所麻煩,我們不能這樣像Not一樣簡單處理:

      public static Expression<Func<T, bool>> And<T>(
          this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
      {
          var candidateExpr = one.Parameters[0];
          var body = Expression.And(one.Body, another.Body);
          return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
      }
      

      這么做雖然能夠編譯通過,但是在執行時便會出錯。原因在于one和another兩個表達式雖然都是同樣的形式(Expression<Func<T, bool>>),但是它們的“參數”不是同一個對象。也就是說,one.Body和another.Body并沒有公用一個ParameterExpression實例,于是我們無論采用哪個表達式的參數,在Expression.Lambda方法調用的時候,都會告訴您新的body中的某個參數對象并沒有出現在參數列表中。

      于是,我們如果要實現And和Or,做的第一件事情便是統一兩個表達式樹的參數,于是我們準備一個ExpressionVisitor:

      internal class ParameterReplacer : ExpressionVisitor
      {
          public ParameterReplacer(ParameterExpression paramExpr)
          {
              this.ParameterExpression = paramExpr;
          }
      
          public ParameterExpression ParameterExpression { get; private set; }
      
          public Expression Replace(Expression expr)
          {
              return this.Visit(expr);
          }
      
          protected override Expression VisitParameter(ParameterExpression p)
          {
              return this.ParameterExpression;
          }
      }
      

      ExpressionVisitor幾乎是處理表達式樹這種數據結構的不二法門,它可以用于求值,變形(其實是生成新的結構,因為表達式樹是immutable的數據結構)等各種操作。例如,解決表達式樹的緩存時用它來求樹的散列值或讀寫前綴樹,快速計算表達式時用它來提取表達式樹的參數,并將不同的表達式樹“標準化”為相同的結構。

      ExpressionVisitor基類的關鍵,就在于提供了遍歷表達式樹的標準方式,如果您直接繼承這個類并調用Visit方法,那么最終返回的結果便是傳入的Expression參數本身。但是,如果您覆蓋的任意一個方法,返回了與傳入時不同的對象,那么最終的結果就會是一個新的Expression對象。ExpressionVisitor類中的每個方法都負責一類表達式,也都都遵循了類似的原則:它們會遞歸地調用Visit方法,如果Visit返回新對象,那么它們也會構造新對象并返回。

      ParameterReplacer類的作用是將一個表達式樹里的所有ParameterExpression替換成我們指定的新對象,因此只需覆蓋VisitParameter方法就可以了。有了它之后,And和Or方法的實現輕而易舉:

      public static Expression<Func<T, bool>> And<T>(
          this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
      {
          var candidateExpr = Expression.Parameter(typeof(T), "candidate");
          var parameterReplacer = new ParameterReplacer(candidateExpr);
      
          var left = parameterReplacer.Replace(one.Body);
          var right = parameterReplacer.Replace(another.Body);
          var body = Expression.And(left, right);
      
          return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
      }
      
      public static Expression<Func<T, bool>> Or<T>(
          this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
      {
          var candidateExpr = Expression.Parameter(typeof(T), "candidate");
          var parameterReplacer = new ParameterReplacer(candidateExpr);
      
          var left = parameterReplacer.Replace(one.Body);
          var right = parameterReplacer.Replace(another.Body);
          var body = Expression.Or(left, right);
      
          return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
      }
      

      于是,我們最終構造得到的Expression<Func<T, bool>>對象便可以傳入一個LINQ Provider,最終得到查詢結果:

      Expression<Func<int, bool>> f = i => i % 2 == 0;
      f = f.Not().And(i => i % 3 == 0).Or(i => i % 4 == 0);
      
      foreach (var i in new int[] { 1, 2, 3, 4, 5, 6 }.AsQueryable().Where(f))
      {
          Console.WriteLine(i);
      }
      

      輸出的結果是3和4。

      這種做法是非常有實用價值的。因為有了LINQ,因此許多朋友都會選擇在數據訪問層暴露一個這樣的方法給上層調用:

      class ProductDao
      {
          public Product GetProduct(Expression<Func<Product, bool>> predicate)
          {
              ...
          }
      }
      

      但是您有沒有想過這么做的缺點是什么呢?這么做的缺點便是“過于自由”。由于GetProduct方法只將參數限制為一個Expression<Func<Product, bool>>對象,因此在調用的時候,我們可以使用任意的形式進行傳遞。因此,外層完全有可能傳入一個目前LINQ Provider不支持的表達式樹形式,也完全有可能傳入一個雖然支持,但會導致查詢速度慢,影響項目整體性能的表達式樹。前者要在運行時才拋出異常,而后者則引發的性能問題則更難發現。因此我認為,數據訪問層不應該如此自由,它要做出限制。而限制的方式,便是使用Query Object模式,讓GetProduct方法接受一個受限的Criteria對象:

      public abstract class ProductCriteria
      {
          internal ProductCriteria(Expression<Func<Product, bool>> query)
          {
              this.Query = query;
          }
      
          public Expression<Func<Product, bool>> Query { get; private set; }
      }
      
      class ProductDao
      {
          public Product GetProduct(ProductCriteria predicate)
          {
              ...
          }
      }
      

      而在使用時,我們只提供有限的幾種條件,如:

      public class ProductIdEqCriteria : ProductCriteria
      {
          public ProductIdEqCriteria(int id)
              : base(p => p.ProductID == id)
          { }
      }
      
      public class ProductViewRangeCriteria : ProductCriteria
      {
          public ProductViewRangeCriteria(int min, int max)
              : base(p => p.ViewCount > min && p.ViewCount < max)
          { }
      }
      

      再加上配套的擴展方法用于And,Or,Not,于是一切盡在掌握?,F在再去瞅瞅原Query Object模式中復雜的實現,您是否會有一種滿足感?

      主站蜘蛛池模板: 福利一区二区在线观看| 国产亚洲精品第一综合| 日本大片在线看黄a∨免费| 高清色本在线www| 麻豆国产成人AV在线播放| 五月开心六月丁香综合色啪| 亚洲熟妇色xxxxx亚洲| 国产一区二区三区精品综合 | 少妇人妻偷人免费观看| 特级做a爰片毛片免费看无码| 在线观看潮喷失禁大喷水无码| 开心久久综合激情五月天| 国产丰满老熟女重口对白| 蜜臀91精品高清国产福利| 亚洲偷自拍国综合| 贵州省| 四虎成人精品无码永久在线| AV人摸人人人澡人人超碰| 丁香婷婷色综合激情五月| 国产精品一二三区蜜臀av| 日韩精品一区二区三区影院| 26uuu另类亚洲欧美日本| 亚洲国产成人无码影片在线播放| 无码免费大香伊蕉在人线国产| 草草浮力地址线路①屁屁影院| 国产精品99久久久久久www| 狠狠婷婷色五月中文字幕| 亚洲国产精品久久久天堂麻豆宅男| 国产精品一区二区蜜臀av| 在线免费观看视频1区| 色伦专区97中文字幕| 亚洲avav天堂av在线网爱情| 真实单亲乱l仑对白视频| 免费无码一区二区三区蜜桃大| www插插插无码免费视频网站 | 亚洲av片在线免费观看| 国产免费午夜福利蜜芽无码| 男女性高爱潮免费网站| 人妻熟女一区二区aⅴ向井蓝| 九九成人免费视频| 亚洲熟妇自偷自拍另类|