[英]How to apply multiple filter conditions (simultaneously) on a list?
I have following C# code with .Net 4.0
framework. 我在.Net 4.0
框架中使用以下C#代码。 This is created after referring The Specification Pattern - by Jeff Perrin 这是在参考“规范模式”之后创建的-Jeff Perrin
In the GetProducts()
the conditions to be used are defined (hard coded) inside the method. 在GetProducts()
中,要使用的条件在方法内部定义(硬编码)。 There is another method named GetProductsBasedOnInputFilters()
. 还有另一个名为GetProductsBasedOnInputFilters()
方法。 In this method the list of specifications are made as parameter to the method. 在此方法中,规格列表作为方法的参数。
QUESTION 题
What is the best way to apply these filters on the list of products, in this method? 用这种方法将这些过滤器应用于产品列表的最佳方法是什么?
Note : I have tried applying the FindAll
clause inside a foreach
loop and adding the results in a list
. 注意 :我尝试在foreach
循环中应用FindAll
子句,并将结果添加到list
。 But that logic is incorrect - only those items that satisfy all of the conditions need to be returned. 但是这种逻辑是不正确的-只有那些满足所有条件的项目才需要返回。
Note : The number of specifications in the productSpeifications list will vary based on user input 注意 :productSpeifications列表中的规格数将根据用户输入而有所不同
Note : The Approach mentioned in " Dynamically build LINQ filter for the Any() method? " seems useful. 注意 :“ 为Any()方法动态构建LINQ筛选器? ”中提到的方法似乎很有用。 However I am not sure how to use this approach here since I am dealing with List of specifications
; 但是由于我正在处理specifications
列表,所以我不确定在这里如何使用这种方法。 not generic delegates
. 不是generic delegates
。
Filter Methods 筛选方法
public static class ProductFilterHelper
{
public static List<Product> GetProducts(List<Product> list)
{
double priceLimit = 100;
//FIRST::
//List<Product> selectedList = list.FindAll(new OnSaleSpecification().IsSatisfiedBy);
//SECOND::
//AndSpecification<Product> spec = new AndSpecification<Product>(new OnSaleSpecificationForProduct(), new PriceGreaterThanSpecificationForProduct(priceLimit));
//List<Product> selectedList = list.FindAll(spec.IsSatisfiedBy);
//THIRD:
List<Product> selectedList = list.FindAll(new OnSaleSpecificationForProduct()
.And(new PriceGreaterThanSpecificationForProduct(priceLimit))
.And(new PriceGreaterThan105())
.IsSatisfiedBy
);
return selectedList;
}
public static List<Product> GetProductsBasedOnInputFilters(List<Product> productList, List<Specification<Product>> productSpeifications)
{
List<Product> selectedList = new List<Product>();
foreach (Specification<Product> specification in productSpeifications)
{
List<Product> 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;
}
}
Client 客户
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();
}
}
Abstract Specifications 摘要规格
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;
}
}
Generic Specifications 通用规格
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);
}
}
Product Specifications 产品规格
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;
}
}
Entity 实体
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; }
}
}
REFERENCES 参考
You can do one of several things: 您可以执行以下操作之一:
Combine the filters by stacking Where
invocations on top of each other, like in @Lijo's answer 通过相互堆叠Where
调用来组合过滤器,如@Lijo的答案
Check all specifications on each item: 检查每个项目的所有规格:
return productList .Where(p => specifications.All(ps => ps.IsSatisfiedBy(p)) .ToList()
Create a composite 'And' specification that accepts multiple children instead of just two: 创建一个复合的“ And”规范,该规范接受多个子代,而不是两个子代:
public class AndSpecification<T> : ISpecification<T> { private ISpecification<T>[] _components; public AndSpecification(ISpecification<T>[] components) { _components = components; } public bool IsSatisfiedBy(T item) { return components.All(c => c.IsSatisfiedBy(item)); } }
Then you could do: 然后,您可以执行以下操作:
var allFiltersSpecification = new AndSpecification(specifications)
return productList.Where(allFiltersSpecification.IsSatisfiedBy);
Following code works... Suggestions are welcome. 以下代码有效...欢迎提出建议。
public static List<Product> GetProductsBasedOnInputFilters(List<Product> productList, List<Specification<Product>> productSpecifications)
{
IEnumerable<Product> selectedList = productList;
foreach (Specification<Product> specification in productSpecifications)
{
selectedList = selectedList.Where(specification.IsSatisfiedBy);
}
return selectedList.ToList();
}
It is worth to take a look at the following too.. 也值得一看以下内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.