添加或EX pressions在LINQ的一个循环

问题描述:

我有不同数量的,我想把他们放在一起成一个LINQ查询的条件。

I have a variable number of OR conditions that I want to put together into one Linq query.

我如何做到这一点在一个循环?基本上,最终查询是成为:

How do I do this in a loop? Basically, the final query is to be:

IQueryable<MyObject> Q;
Q = Q.Where(q => (condition1) || (condition2) || ..... || (condition N));

是这样的:

For (int i = 0; i < someNumber; i++) {
  Q = Q.Where(q => (existing conditions) || (q.Value == i)); 
}

我可以用什么语句来代替的(现有的条件)的例子在上面,而无需最终EX pression(Q)有嵌套Q记者在他们里面?

What statement can I use to replace (existing condition) in example above without having the final expression (Q) have nested Q's inside them?

感谢。

您需要构建一个前pression树重新presenting所有你感兴趣的条件,再加上防爆pression.OrElse ,然后调用其中,在最后一次。

You'd need to build an expression tree representing all the conditions you were interested in, combined with Expression.OrElse, and then call Where a single time at the end.

这可能是有点棘手,如果你的电流源是一个匿名的类型,但它不应该是太糟糕了,否则。下面是一个样本 - 有可能是做参数更换更简单的方法,但是这是不是太糟糕。 (虽然防爆pressionVisitor 只能在.NET 4 ...你必须自己实现类似的东西,如果你想使用这个在.NET 3.5)。

This may be somewhat tricky if your current source is an anonymous type, but it shouldn't be too bad otherwise. Here's a sample - there may be a simpler way of doing the parameter replacement, but this isn't too bad. (Although ExpressionVisitor only works in .NET 4... you'd have to implement something similar yourself if you wanted to use this in .NET 3.5.)

using System;
using System.Linq;
using System.Linq.Expressions;

public class Test
{
    static void Main()
    {
        IQueryable<string> strings = (new[] { "Jon", "Tom", "Holly", 
             "Robin", "William" }).AsQueryable();


        Expression<Func<string, bool>> firstPredicate = p => p.Contains("ll");
        Expression<Func<string, bool>> secondPredicate = p => p.Length == 3;
        Expression combined = Expression.OrElse(firstPredicate.Body,
                                                secondPredicate.Body);

        ParameterExpression param = Expression.Parameter(typeof(string), "p");
        ParameterReplacer replacer = new ParameterReplacer(param);
        combined = replacer.Visit(combined);

        var lambda = Expression.Lambda<Func<string, bool>>(combined, param);

        var query = strings.Where(lambda);

        foreach (string x in query)
        {
            Console.WriteLine(x);
        }
    }

    // Helper class to replace all parameters with the specified one
    class ParameterReplacer : ExpressionVisitor
    {
        private readonly ParameterExpression parameter;

        internal ParameterReplacer(ParameterExpression parameter)
        {
            this.parameter = parameter;
        }

        protected override Expression VisitParameter
            (ParameterExpression node)
        {
            return parameter;
        }
    }
}