2

Этот вопрос является усовершенствованием уже ответил вопросом 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(); 
    } 

Нам нужно создать новый метод (GetProductsUisngDynamicFilters), который способен выполнять AND, OR и NOT спецификации (и сочетание этого). Любая идея, как мы можем это решить?

Методы фильтра

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

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

} 

Аннотация Характеристики

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

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

ответ

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> в метод расширения. И, возможно, вместо этого используйте интерфейсы.

 Смежные вопросы

  • Нет связанных вопросов^_^