如何动态地结合条件

如何动态地结合条件

本文介绍了如何动态地结合条件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是一个增强已经回答问题的



在上面提到的问题,我们有一个应用的方法对所有规格和运营商。这是通过使用LINQ 的规格全部运算符来实现的。

 公开静态列表<产品与GT; GetProductsUisngAndFilters(列表<产品> productList的,列表与LT;规格及LT;产品>> productSpecifications)
{
返回productList.Where(P => productSpecifications.All(PS => ps.IsSatisfiedBy(P) ))了ToList()。
}

我们需要创建一个新的方法(GetProductsUisngDynamicFilters)能够执行的不是规范(和一个混合)。任何想法如何解决呢?



过滤方法



 公共静态类ProductFilterHelper 
{
公共静态列表<产品与GT; GetProductsUisngAndFilters(列表<产品> productList的,列表与LT;规格及LT;产品>> productSpecifications)
{
返回productList.Where(P => productSpecifications.All(PS => ps.IsSatisfiedBy(P) ))了ToList()。
}
}



客户端

 类节目
{

静态无效的主要(字串[] args)
{

名单,LT;产品与GT;名单=新名单,LT;产品>();

产品P1 =新产品(假,99);
产品P2 =新产品(真,99);
产品P3 =新产品(真正的,101);
产品P4 =新产品(真正的,110);
产品P5 =新产品(假的,110);

list.Add(P1);
list.Add(P2);
list.Add(P3);
list.Add(P4);
list.Add(P5);

双priceLimit = 100;

名单,LT;规格及LT;产品与GT;>规格=新的List<规格及LT;产品与GT;>();
specifications.Add(新OnSaleSpecificationForProduct());
specifications.Add(新PriceGreaterThanSpecificationForProduct(pr​​iceLimit));
specifications.Add(新PriceGreaterThan105());

名单,LT;产品与GT; selectedList = ProductFilterHelper.GetProductsBasedOnInputFilters(列表,规格);

Console.ReadKey();
}

}



摘要规格

 公共抽象类规格及LT; T> 
{
公共抽象BOOL IsSatisfiedBy(T OBJ);

公共AndSpecification< T>和(规格及LT; T>规范)
{
返回新AndSpecification< T>(这一点,规范);
}

公共OrSpecification< T>或(规格及LT; T>规范)
{
返回新OrSpecification< T>(这一点,规范);
}

公共NotSpecification< T>没有(规格及LT; T>规范)
{
返回新NotSpecification< T>(这一点,规范);
}
}

公共抽象类CompositeSpecification< T> :指标LT; T>
{
保护只读规格及LT; T> _左边;
保护只读规格及LT; T> _右边;

公共CompositeSpecification(规格及LT; T> leftSide,规格及LT; T> rightSide)
{
_leftSide = leftSide;
_rightSide = rightSide;
}
}



通用规格

 公共类AndSpecification< T> :CompositeSpecification< T> 
{
公共AndSpecification(规格及LT; T> leftSide,规格及LT; T> rightSide)
:基地(leftSide,rightSide)
{

}

酒店的公共覆盖布尔IsSatisfiedBy(T OBJ)
{
返回_leftSide.IsSatisfiedBy(OBJ)及和放大器; _rightSide.IsSatisfiedBy(OBJ);
}
}

公共类OrSpecification< T> :CompositeSpecification< T>
{
公共OrSpecification(规格及LT; T> leftSide,规格及LT; T> rightSide)
:基地(leftSide,rightSide)
{
}

酒店的公共覆盖布尔IsSatisfiedBy(T OBJ)
{
返回_leftSide.IsSatisfiedBy(OBJ)|| _rightSide.IsSatisfiedBy(OBJ);
}
}

公共类NotSpecification< T> :CompositeSpecification< T>
{
公共NotSpecification(规格及LT; T> leftSide,规格及LT; T> rightSide)
:基地(leftSide,rightSide)
{
}

酒店的公共覆盖布尔IsSatisfiedBy(T OBJ)
{
返回_leftSide.IsSatisfiedBy(OBJ)及和放大器; !_rightSide.IsSatisfiedBy(OBJ);
}
}



产品规格

 公共类OnSaleSpecificationForProduct:指标LT;产品与GT; 
{
公众覆盖布尔IsSatisfiedBy(产品产品)
{
返回product.IsOnSale;
}
}

公共类PriceGreaterThanSpecificationForProduct:指标LT;产品与GT;
{
私人只读双_price;
公共PriceGreaterThanSpecificationForProduct(双价)
{
_price =价格;
}

公众覆盖布尔IsSatisfiedBy(产品产品)
{
返回product.Price> _价钱;
}
}

公共类PriceGreaterThan105:指标LT;产品与GT;
{

公众覆盖布尔IsSatisfiedBy(产品产品)
{
返回product.Price> 105;
}
}



实体

 公共类产品
{
私人布尔_isOnSale;
私人双_price = 0.0;

公共产品(布尔isOnSale)
:这(isOnSale,0.0)
{
_isOnSale = isOnSale;
}

公共产品(双价)
:这个(假的,价格)
{
_price =价格;
}

公共产品(布尔isOnSale,双价)
{
_price =价格;
_isOnSale = isOnSale;
}

公共BOOL IsOnSale
{
{返回_isOnSale; }
}

公共双价
{
{返回_price; }
}
}


解决方案

通过查看您所提供的代码,它在我看来,你的过滤器相结合的逻辑是健全的。问题是列表与LT;规格及LT; T>> 。通过在地方有复合的规范,你可以将它们结合起来,只有通过一个规范< T> (这将是一个 CompositeSpecification< T> ):

 类节目
{

静态无效的主要(字符串[]参数)
{

名单,LT;产品与GT;名单=新名单,LT;产品>();

产品P1 =新产品(假,99);
产品P2 =新产品(真,99);
产品P3 =新产品(真正的,101);
产品P4 =新产品(真正的,110);
产品P5 =新产品(假的,110);

list.Add(P1);
list.Add(P2);
list.Add(P3);
list.Add(P4);
list.Add(P5);

双priceLimit = 100;

变种规格=
新OnSaleSpecificationForProduct()
。而(新PriceGreaterThanSpecificationForProduct(pr​​iceLimit)
。或者(新PriceGreaterThan105()));

名单,LT;产品与GT; selectedList = ProductFilterHelper.GetProductsBasedOnInputFilters(列表,规格);

Console.ReadKey();
}

}

和您的滤波方法变为:

 公共静态列表<产品与GT; GetProductsUisngDynamicFilters(列表<产品> productList的,规格及LT;产品> productSpecification)
{
返回productList.Where(P => productSpecification.IsSatisfiedBy(P))
.ToList();
}



作为一个方面说明,你应该考虑移动从抽象规格及LT法; T> 来扩展方法。也许使用接口来代替。


This question is an enhancement to the already answered question How to apply multiple filter conditions (simultaneously) on a list?

In the above mentioned question we have a method that applied AND operator on all the specifications. This is achieved by using LINQ All operator on the specifications.

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

We need to create a new method (GetProductsUisngDynamicFilters) that is capable of performing AND, OR and NOT specifications (and a mix of that). Any idea how we can solve this?

Filter Methods

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

}

Abstract Specifications

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

Generic Specifications

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; }
    }
}
解决方案

By looking at the code you provided, it seems to me that your logic for combining filters is sound. The problem is the List<Specification<T>>. By having compound specification in place, you can combine them and only pass a Specification<T> (which would be a 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();
    }

}

And your filtering method becomes:

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

As a side note, you should consider moving the Or, And and Not method from the abstract Specification<T> to an extension method. And perhaps use interfaces instead.

这篇关于如何动态地结合条件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-31 00:04