Come combinare le condizioni in modo dinamico?

Questa domanda è un miglioramento della domanda già risposta Come applicare più condizioni di filtro (simultaneamente) in un elenco?

Nella domanda di cui sopra abbiamo un metodo che applica l’operatore AND su tutte le specifiche. Ciò si ottiene utilizzando l’operatore LINQ All sulle specifiche.

  public static List GetProductsUisngAndFilters(List productList, List<Specification> productSpecifications) { return productList.Where(p => productSpecifications.All(ps => ps.IsSatisfiedBy(p))).ToList(); } 

Abbiamo bisogno di creare un nuovo metodo (GetProductsUisngDynamicFilters) che sia in grado di eseguire le specifiche AND , OR e NOT (e un mix di quello). Qualche idea su come possiamo risolvere questo?

Metodi di filtro

 public static class ProductFilterHelper { public static List GetProductsUisngAndFilters(List productList, List<Specification> productSpecifications) { return productList.Where(p => productSpecifications.All(ps => ps.IsSatisfiedBy(p))).ToList(); } } 

Cliente

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

Specifiche astratte

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

Specifiche generiche

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

specifiche del prodotto

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

Entità

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

Osservando il codice che hai fornito, mi sembra che la tua logica per combinare i filtri sia sana. Il problema è l’ List> . Avendo una specifica composta, è ansible combinarli e passare solo una Specification (che sarebbe una Specification CompositeSpecification ):

 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; var specification = new OnSaleSpecificationForProduct() .And(new PriceGreaterThanSpecificationForProduct(priceLimit) .Or(new PriceGreaterThan105())); List selectedList = ProductFilterHelper.GetProductsBasedOnInputFilters(list, specification); Console.ReadKey(); } } 

E il tuo metodo di filtraggio diventa:

  public static List GetProductsUisngDynamicFilters(List productList, Specification productSpecification) { return productList.Where(p => productSpecification.IsSatisfiedBy(p)) .ToList(); } 

Come nota a margine, dovresti considerare di spostare il metodo Or , And e Not dalla Specification astratta Specification in un metodo di estensione. E forse usa invece le interfacce.