如何动态组合条件?

此问题是对已经回答的问题的增强如何在列表中应用多个过滤条件(同时)?

在上面提到的问题中,我们有一个方法,在所有规范上应用AND运算符。 这是通过在规范上使用LINQ All运算符来实现的。

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

我们需要创建一个能够执行ANDORNOT规范(以及它的混合)的新方法(GetProductsUisngDynamicFilters)。 知道怎么解决这个问题吗?

过滤方法

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

客户

 class Program { static void Main(string[] args) { List list = new List(); 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> specifications = new List<Specification>(); specifications.Add(new OnSaleSpecificationForProduct()); specifications.Add(new PriceGreaterThanSpecificationForProduct(priceLimit)); specifications.Add(new PriceGreaterThan105()); List selectedList = ProductFilterHelper.GetProductsBasedOnInputFilters(list, specifications); Console.ReadKey(); } } 

摘要规格

 public abstract class Specification { public abstract bool IsSatisfiedBy(T obj); public AndSpecification And(Specification specification) { return new AndSpecification(this, specification); } public OrSpecification Or(Specification specification) { return new OrSpecification(this, specification); } public NotSpecification Not(Specification specification) { return new NotSpecification(this, specification); } } public abstract class CompositeSpecification : Specification { protected readonly Specification _leftSide; protected readonly Specification _rightSide; public CompositeSpecification(Specification leftSide, Specification rightSide) { _leftSide = leftSide; _rightSide = rightSide; } } 

通用规范

 public class AndSpecification : CompositeSpecification { public AndSpecification(Specification leftSide, Specification rightSide) : base(leftSide, rightSide) { } public override bool IsSatisfiedBy(T obj) { return _leftSide.IsSatisfiedBy(obj) && _rightSide.IsSatisfiedBy(obj); } } public class OrSpecification : CompositeSpecification { public OrSpecification(Specification leftSide, Specification rightSide) : base(leftSide, rightSide) { } public override bool IsSatisfiedBy(T obj) { return _leftSide.IsSatisfiedBy(obj) || _rightSide.IsSatisfiedBy(obj); } } public class NotSpecification : CompositeSpecification { public NotSpecification(Specification leftSide, Specification rightSide) : base(leftSide, rightSide) { } public override bool IsSatisfiedBy(T obj) { return _leftSide.IsSatisfiedBy(obj) && !_rightSide.IsSatisfiedBy(obj); } } 

产品规格

 public class OnSaleSpecificationForProduct : Specification { public override bool IsSatisfiedBy(Product product) { return product.IsOnSale; } } public class PriceGreaterThanSpecificationForProduct : Specification { private readonly double _price; public PriceGreaterThanSpecificationForProduct(double price) { _price = price; } public override bool IsSatisfiedBy(Product product) { return product.Price > _price; } } public class PriceGreaterThan105 : Specification { 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; } } } 

通过查看您提供的代码,在我看来,组合filter的逻辑是合理的。 问题是List> 。 通过使用复合规范,您可以组合它们并仅传递Specification (这将是CompositeSpecification ):

 class Program { static void Main(string[] args) { List list = new List(); 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 selectedList = ProductFilterHelper.GetProductsBasedOnInputFilters(list, specification); Console.ReadKey(); } } 

并且您的过滤方法变为:

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

作为旁注,您应该考虑将OrAndNot方法从抽象Specification到扩展方法。 也许使用接口代替。