Как применить несколько условий фильтра (одновременно) к списку?

У меня есть следующий код 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 ()?

Ответы на вопрос(2)

Ваш ответ на вопрос