How to apply multiple filter conditions (simultaneously) in a list?

I have a C # code with a framework .Net 4.0. This is created after accessing the Specification Template by Jeff Perrin.

The GetProducts()conditions that will be used are defined (hardcoded) inside the method. There is another method named GetProductsBasedOnInputFilters(). In this method, a list of specifications is made as a parameter for the method.

Question

What is the best way to apply these filters to the product list in this method?

Note . I tried to apply the sentence FindAllinside the loop foreachand add the results to list. But this logic is incorrect - only those elements that satisfy all conditions are required to be returned .

Note . The number of specifications in the product list depends on the user.

Note . The approach mentioned in Dynamically creating a LINQ filter for the Any ()? Method seems useful. However, I'm not sure how to use this approach here, since I'm dealing with a list specifications; not 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 characteristics

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

General characteristics

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

LITERATURE

0
2

:

  • , Where , @Lijo

  • :

    return productList
      .Where(p => specifications.All(ps => ps.IsSatisfiedBy(p))
      .ToList()
    
  • "", :

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

:

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

... .

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

.

+1

Source: https://habr.com/ru/post/1726884/


All Articles