Adding OR expressions in a loop in Linq

后端 未结 3 1186
死守一世寂寞
死守一世寂寞 2021-02-05 19:17

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

相关标签:
3条回答
  • 2021-02-05 19:36

    A less-than-optimized version (pray that the backend will do the necessary lifting and optimization).

    public static IQueryable<T> Any<T>(this IQueryable<T> q, 
      params Expression<Func<T, bool>>[] preds)
    {
      var par = Expression.Parameter(typeof(T), "x");
    
      Expression body = Expression.Constant(false);
    
      foreach (var pred in preds)
      {
        body = Expression.OrElse(body, Expression.Invoke(pred, par));
      }
    
      var ff = Expression.Lambda(body, par) as Expression<Func<T, bool>>;
    
      return q.Where(ff);
    }
    
    static void Main(string[] args)
    {
      var q = new[] { "jim", "bob", "Jon", "leppie" }.AsQueryable();
    
      Expression<Func<string, bool>>[] preds =
      {
        x => x == "Jon",
        x => x == "Skeet",
        x => x == "leppie"
      };
    
      var result = q.Any(preds).ToArray();
    }
    
    0 讨论(0)
  • 2021-02-05 19:39

    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.

    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;
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-05 19:43
      public static IEnumerable<T> GetItemsThatMatchAny<T> (this IEnumerable<T> source, IEnumerable<Func<T,bool>> predicates)
        {      
          return source.Where(t => predicates.Any(predicate => predicate(t)));
        }
    

    An example of a predicate generator:

    private static IEnumerable<Func<MyClass, bool>> GetPredicates (int num)
    {
       var predicates = new Func<MyClass, bool>[] {m => m.Foo == 3, m => m.Bar =="x", m => DateTime.Now.DayOfWeek == DayOfWeek.Sunday};
    
       return predicates.Take (num);
    }
    
    0 讨论(0)
提交回复
热议问题