如何在列表中应用多个过滤条件(同时)?

我使用.Net 4.0框架跟随C#代码。 这是在参考规范模式后由Jeff Perrin创建的

GetProducts()中,要使用的条件在方法内定义(硬编码)。 还有另一种名为GetProductsBasedOnInputFilters()方法。 在此方法中,规范列表作为方法的参数。

在此方法中,在产品列表中应用这些filter的最佳方法是什么?

注意 :我尝试在foreach循环中应用FindAll子句并将结果添加到list 。 但是这种逻辑是不正确的 – 只需要返回那些满足所有条件的项目。

注意 :productSpeifications列表中的规格数量会因用户输入而异

注意 :“ 为Any()方法动态构建LINQfilter? ”中提到的方法似乎很有用。 但是我不知道如何在这里使用这种方法,因为我正在处理specifications列表; 不是generic delegates

过滤方法

 public static class ProductFilterHelper { public static List GetProducts(List list) { double priceLimit = 100; //FIRST:: //List selectedList = list.FindAll(new OnSaleSpecification().IsSatisfiedBy); //SECOND:: //AndSpecification spec = new AndSpecification(new OnSaleSpecificationForProduct(), new PriceGreaterThanSpecificationForProduct(priceLimit)); //List selectedList = list.FindAll(spec.IsSatisfiedBy); //THIRD: List selectedList = list.FindAll(new OnSaleSpecificationForProduct() .And(new PriceGreaterThanSpecificationForProduct(priceLimit)) .And(new PriceGreaterThan105()) .IsSatisfiedBy ); return selectedList; } public static List GetProductsBasedOnInputFilters(List productList, List<Specification> productSpeifications) { List selectedList = new List(); foreach (Specification specification in productSpeifications) { List currentList = productList.FindAll(specification.IsSatisfiedBy); if (currentList != null && currentList.Count > 0) { foreach (Product p in currentList) { if (!selectedList.Contains(p)) { selectedList.Add(p); } } } } return selectedList; } } 

客户

 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; } } } 

参考

  1. 规范模式 – 由Jeff Perrin撰写
  2. C#中的流畅接口和方法链接
  3. 避免使用linq多次浏览列表,具有动态条件(filter)
  4. 动态构建Any()方法的LINQfilter?

你可以做以下几件事之一:

  • 通过堆叠Where调用彼此之上的过滤来组合filter,就像@Lijo的答案一样

  • 检查每个项目的所有规格:

     return productList .Where(p => specifications.All(ps => ps.IsSatisfiedBy(p)) .ToList() 
  • 创建一个复合’And’规范,接受多个子节点而不是两个:

     public class AndSpecification : ISpecification { private ISpecification[] _components; public AndSpecification(ISpecification[] components) { _components = components; } public bool IsSatisfiedBy(T item) { return components.All(c => c.IsSatisfiedBy(item)); } } 

然后你可以这样做:

 var allFiltersSpecification = new AndSpecification(specifications) return productList.Where(allFiltersSpecification.IsSatisfiedBy); 

以下代码工作…欢迎提出建议。

  public static List GetProductsBasedOnInputFilters(List productList, List> productSpecifications) { IEnumerable selectedList = productList; foreach (Specification specification in productSpecifications) { selectedList = selectedList.Where(specification.IsSatisfiedBy); } return selectedList.ToList(); } 

值得一看的还有以下内容……

  1. 表达树基础知识
  2. 在Visual Studio 2010中使用表达式树生成动态方法
  3. 动态编写表达式谓词
  4. 如何动态组合条件?