此问题是对已回答的问题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();
}
我们需要创建一个能够执行AND
,OR
和NOT
规范(及其混合)的新方法(GetProductsUisngDynamicFilters)。知道如何解决这个问题吗?
过滤方法
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; }
}
}
答案 0 :(得分: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();
}
作为旁注,您应该考虑将Or
,And
和Not
方法从抽象Specification<T>
移动到扩展方法。也许可以使用接口。