2

這個問題是一個增強已經回答的問題How to apply multiple filter conditions (simultaneously) on a list?如何動態組合條件?

在上面提到的問題,我們有所有的規格適用AND操作的方法。這是通過使用LINQ All運營商的規格來實現的。

public static List<Product> GetProductsUisngAndFilters(List<Product> productList, List<Specification<Product>> productSpecifications) 
    { 
     return productList.Where(p => productSpecifications.All(ps => ps.IsSatisfiedBy(p))).ToList(); 
    } 

我們需要創建一個新的方法(GetProductsUisngDynamicFilters),它能夠執行ANDORNOT規格(和一個混合)的。任何想法我們如何解決這個問題?

濾波方法

public static class ProductFilterHelper 
{ 
    public static List<Product> GetProductsUisngAndFilters(List<Product> productList, List<Specification<Product>> productSpecifications) 
    { 
     return productList.Where(p => productSpecifications.All(ps => ps.IsSatisfiedBy(p))).ToList(); 
    } 
} 

客戶

class Program 
{ 

    static void Main(string[] args) 
    { 

     List<Product> list = new List<Product>(); 

     Product p1 = new Product(false, 99); 
     Product p2 = new Product(true, 99); 
     Product p3 = new Product(true, 101); 
     Product p4 = new Product(true, 110); 
     Product p5 = new Product(false, 110); 

     list.Add(p1); 
     list.Add(p2); 
     list.Add(p3); 
     list.Add(p4); 
     list.Add(p5); 

     double priceLimit = 100; 

     List<Specification<Product>> specifications = new List<Specification<Product>>(); 
     specifications.Add(new OnSaleSpecificationForProduct()); 
     specifications.Add(new PriceGreaterThanSpecificationForProduct(priceLimit)); 
     specifications.Add(new PriceGreaterThan105()); 

     List<Product> selectedList = ProductFilterHelper.GetProductsBasedOnInputFilters(list, specifications); 

     Console.ReadKey(); 
    } 

} 

摘要規格

public abstract class Specification<T> 
{ 
    public abstract bool IsSatisfiedBy(T obj); 

    public AndSpecification<T> And(Specification<T> specification) 
    { 
     return new AndSpecification<T>(this, specification); 
    } 

    public OrSpecification<T> Or(Specification<T> specification) 
    { 
     return new OrSpecification<T>(this, specification); 
    } 

    public NotSpecification<T> Not(Specification<T> specification) 
    { 
     return new NotSpecification<T>(this, specification); 
    } 
} 

public abstract class CompositeSpecification<T> : Specification<T> 
{ 
    protected readonly Specification<T> _leftSide; 
    protected readonly Specification<T> _rightSide; 

    public CompositeSpecification(Specification<T> leftSide, Specification<T> rightSide) 
    { 
     _leftSide = leftSide; 
     _rightSide = rightSide; 
    } 
} 

個通用規範

public class AndSpecification<T> : CompositeSpecification<T> 
{ 
    public AndSpecification(Specification<T> leftSide, Specification<T> rightSide) 
     : base(leftSide, rightSide) 
    { 

    } 

    public override bool IsSatisfiedBy(T obj) 
    { 
     return _leftSide.IsSatisfiedBy(obj) && _rightSide.IsSatisfiedBy(obj); 
    } 
} 

public class OrSpecification<T> : CompositeSpecification<T> 
{ 
    public OrSpecification(Specification<T> leftSide, Specification<T> rightSide) 
     : base(leftSide, rightSide) 
    { 
    } 

    public override bool IsSatisfiedBy(T obj) 
    { 
     return _leftSide.IsSatisfiedBy(obj) || _rightSide.IsSatisfiedBy(obj); 
    } 
} 

public class NotSpecification<T> : CompositeSpecification<T> 
{ 
    public NotSpecification(Specification<T> leftSide, Specification<T> rightSide) 
     : base(leftSide, rightSide) 
    { 
    } 

    public override bool IsSatisfiedBy(T obj) 
    { 
     return _leftSide.IsSatisfiedBy(obj) && !_rightSide.IsSatisfiedBy(obj); 
    } 
} 

產品規格

public class OnSaleSpecificationForProduct : Specification<Product> 
{ 
    public override bool IsSatisfiedBy(Product product) 
    { 
     return product.IsOnSale; 
    } 
} 

public class PriceGreaterThanSpecificationForProduct : Specification<Product> 
{ 
    private readonly double _price; 
    public PriceGreaterThanSpecificationForProduct(double price) 
    { 
     _price = price; 
    } 

    public override bool IsSatisfiedBy(Product product) 
    { 
     return product.Price > _price; 
    } 
} 

public class PriceGreaterThan105 : Specification<Product> 
{ 

    public override bool IsSatisfiedBy(Product product) 
    { 
     return product.Price > 105; 
    } 
} 

實體

public class Product 
{ 
    private bool _isOnSale; 
    private double _price = 0.0; 

    public Product(bool isOnSale) 
     : this(isOnSale, 0.0) 
    { 
     _isOnSale = isOnSale; 
    } 

    public Product(double price) 
     : this(false, price) 
    { 
     _price = price; 
    } 

    public Product(bool isOnSale, double price) 
    { 
     _price = price; 
     _isOnSale = isOnSale; 
    } 

    public bool IsOnSale 
    { 
     get { return _isOnSale; } 
    } 

    public double Price 
    { 
     get { return _price; } 
    } 
} 

回答

4

通過查看您所提供的代碼,在我看來,你的邏輯組合濾波器是健全的。問題是List<Specification<T>>。通過到位的化合物具有規範,可以將它們結合起來,只有通過一個Specification<T>(這將是一個CompositeSpecification<T>):

class Program 
{ 

    static void Main(string[] args) 
    { 

     List<Product> list = new List<Product>(); 

     Product p1 = new Product(false, 99); 
     Product p2 = new Product(true, 99); 
     Product p3 = new Product(true, 101); 
     Product p4 = new Product(true, 110); 
     Product p5 = new Product(false, 110); 

     list.Add(p1); 
     list.Add(p2); 
     list.Add(p3); 
     list.Add(p4); 
     list.Add(p5); 

     double priceLimit = 100; 

     var specification = 
      new OnSaleSpecificationForProduct() 
       .And(new PriceGreaterThanSpecificationForProduct(priceLimit) 
           .Or(new PriceGreaterThan105())); 

     List<Product> selectedList = ProductFilterHelper.GetProductsBasedOnInputFilters(list, specification); 

     Console.ReadKey(); 
    } 

} 

而且你的濾波方法變爲:

public static List<Product> GetProductsUisngDynamicFilters(List<Product> productList, Specification<Product> productSpecification) 
    { 
     return productList.Where(p => productSpecification.IsSatisfiedBy(p)) 
          .ToList(); 
    } 

作爲一個側面說明,你應考慮移動從抽象Specification<T>OrAndNot方法的擴展方法。也許可以使用接口。