2010-08-11 19 views
13

Bir Linq sorgusunda bir araya getirmek istediğim VEYA değişken bir değişken numaram var.Linq'de bir döngüde OR ifadeleri ekleme

Bunu bir döngüde nasıl yaparım?

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

şey gibi: Temel olarak, nihai sorgu olmaktır

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

Yukarıda nihai ifadesini kalmadan (Q) örnekte (mevcut durum) değiştirmek için kullanabileceğiniz ne deyim iç içe Q var mı?

Teşekkürler.

cevap

16

Expression.OrElse ile birlikte, ilgilendiğiniz tüm koşulları temsil eden bir ifade ağacı oluşturmanız ve ardından Where numaralı telefonu tek bir zamanda aramanız gerekir.

Geçerli kaynağınız anonim bir tür ise bu biraz zor olabilir, ancak aksi halde çok kötü olmamalıdır. İşte bir örnek - parametre değiştirmenin daha basit bir yolu olabilir, ancak bu çok da kötü değil. (ExpressionVisitor yalnızca .NET 4 çalışmakla beraber .NET 3.5 bu kullanmak istiyorsa ... kendin benzer bir şey uygulamak gerekir.)

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

Sadece neye ihtiyacım vardı: D –

+0

Replacer tam olarak ne yapıyor? – seebiscuit

+0

@Seabiscuit: Temel olarak, ortaya çıkan ifade ağacındaki tüm parametre ifadelerinin, üst düzey ve "alt ifadelerin" her biri için ayrı olanlardan değil, aynı parametre ifadesine başvurmasıdır. –

2
public static IEnumerable<T> GetItemsThatMatchAny<T> (this IEnumerable<T> source, IEnumerable<Func<T,bool>> predicates) 
    {  
     return source.Where(t => predicates.Any(predicate => predicate(t))); 
    } 

bir yüklem jeneratörün örneği:

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

Benzer bir fikrim var ama maalesef bu Linq2Sql ile başarısız. – leppie

+1

Evet, haklısınız; IQueryable bitini özledim. – Ani

2

En iyi duruma getirilmiş bir sürümü (arka ucun gerekli kaldırma ve optimizasyonu yapacağı konusunda dua edin).

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

Linq ro entities için çalışmıyor – moyomeh