Как применить несколько условий фильтра (одновременно) к списку?
У меня есть следующий код C # с.Net 4.0
фреймворк. Это создается после обращенияШаблон спецификации - Джефф Перрен
вGetProducts()
условия, которые будут использоваться, определены (жестко закодированы) внутри метода. Есть еще один метод с именемGetProductsBasedOnInputFilters()
, В этом методе список спецификаций составляется как параметр метода.
ВОПРОС
Каков наилучший способ применения этих фильтров в списке продуктов, в этом методе?
Заметка: Я пытался применитьFindAll
пункт внутриforeach
цикл и добавление результатов вlist
, Но эта логика неверна - только те элементы, которые удовлетворяютвсе условия должны быть возвращены.
Заметка: Количество спецификаций в списке productSpeifications будет зависеть от ввода пользователя
Заметка: Подход, упомянутый вДинамически создавать фильтр LINQ для метода Any ()? " кажется полезным. Однако я не уверен, как использовать этот подход здесь, так как я имею дело со списком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 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 specifications = new List();
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; }
}
}
РЕКОМЕНДАЦИИ
Шаблон спецификации - Джефф ПерренСвободные интерфейсы и метод цепочки в C #Избегайте просмотра списка несколько раз с помощью linq, с динамическими условиями (фильтр)Динамически построить фильтр LINQ для метода Any ()?