简体   繁体   English

简洁的LINQ过滤器表达式

[英]Succinct LINQ filter expression

I have an MVC controller that will filter a product list based on a category. 我有一个MVC控制器,它将根据类别过滤产品列表。

Products = repository.Products.Where(p => category == null || p.Category1 == "category1" );

If I wanted to let the user filter the product with two categories, I would have to add in another if statement that contains Category1 and Category2. 如果我想让用户用两个类别过滤产品,则必须添加另一个包含Category1和Category2的if语句。 I can imagine if I have more categories, and the user can choose category 1,3,5 and so on, the permutation will get crazily large. 我可以想象如果我有更多类别,并且用户可以选择类别1,3,5,依此类推,排列将变得异常庞大。

Is there a proper way of doing this? 有适当的方法吗?

I am assuming that your object model is defined along the lines of: 我假设您的对象模型是按照以下定义的:

public class Product
{
    // ...
    public Category Category1 { get; set; }
    public Category Category2 { get; set; }
    public Category Category3 { get; set; }
    // ...
}

(where you might be using strings instead of having a category class) (您可能使用字符串而不是类别类)

If the object model is within your control, then I would recommend changing it so that a product has a collection of categories rather than several named properties for Category1, Category2, Category3 etc, so more like this: 如果对象模型在您的控制之内,则建议您对其进行更改,以使产品具有类别的集合,而不是Category1,Category2,Category3等的多个命名属性,因此更像这样:

public class Product
{
    // ...
    public IList<Category> Categories { get; set; }
    // ...
}

If the product class is fixed and it already has multiple individual category properties, I would recommend writing an extension method for your product class that returns a list of categories that are non-null. 如果产品类是固定的,并且已经具有多个单独的类别属性,则建议为您的产品类编写扩展方法,该方法将返回非空类别列表。 That way you can write a where expression more succinctly. 这样,您可以更简洁地编写where表达式。

For example: 例如:

public static class ProductExtension
{
    public static IList<Category> GetCategories(this Product product)
    {
        List<Category> categories = new List<Category>();

        if (product.Category1 != null)
        {
            categories.Add(product.Category1);
        }
        if (product.Category2 != null)
        {
            categories.Add(product.Category2);
        }
        // etc.

        return categories;
    }
}

...which could then be used along the lines of ...然后可以按照以下方式使用

repository.Products.Where(p => p.GetCategories().Contains("category1"));

Another option is to create a ProductFilter object to do the filtering for you. 另一个选择是创建一个ProductFilter对象来为您进行过滤。

Give the ProductFilter class a field for every category that is possible to filter on, which each store predicates, and a PassesFilter(Product p) method which determines whether p passes the predicate for all categories where a predicate has been set, eg 给ProductFilter类一个可以过滤的每个类别的字段,每个类别都存储谓词,并为PassesFilter(Product p)方法确定是否p传递了已设置谓词的所有类别的谓词,例如

method PassesFilter(Product p):
   if Category1Filter is not null:
       if p does not pass Category1Filter:
           return false
    if Category2Filter is not null:
       if p does not pass Category2Filter:
           return false
    return true

(Excuse the pseudo-code, I don't do C# and it's late) (对不起,伪代码,我不做C#,这很晚了)

So you could use it like so: 因此,您可以像这样使用它:

ProductFilter pf = new ProductFilter();
...
/*build up your filters for all categories that apply in this search...*/
pf.ColourFilter = (Product p) => { return p.Colour == "Red"; };
pf.PriceFilter = (Product p) => { return p.Price > 100.00; };
...
Products = repository.Products.Where(p => category == null || pf.PassesFilter(p) );

You could also easily implement the PassesFilter method differently to handle OR instead of AND (or create a class for each implementation). 您还可以轻松地以不同的方式轻松实现PassesFilter方法,以处理OR而不是AND(或为每个实现创建一个类)。

I know that using predicates in the way I described would allow you to put a price predicate in the colour predicate field, but I just thought I'd throw this example out there to illustrate the concept of using an object to do the work of lambdas :-) 我知道以我所描述的方式使用谓词将使您可以在颜色谓词字段中放入价格谓词,但是我只是想将这个示例放在此处,以说明使用对象来执行lambda的工作的概念。 :-)

1.You may use Expression to constructor condition expression 1.您可以使用Expression来构造条件表达式

2.Use expression in the linq. 2.在linq中使用表达式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM