2010-05-30 15 views
5

Dinamik olarak birden çok OR "cümlesi" içeren LINQ ifadeleri oluşturmak için bir kod kullanıyorum (MSDN üzerinde here kullanılabilir).'tree' LINQ ifadeleri yerine 'flat' yapı

ilgili koddur

var equals = values.Select(value => (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue)))); 

var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal)); 

Bu şuna benzer bir LINQ ifadesini oluşturur:

(((((ID = 5) OR (ID = 4)) OR (ID = 3)) OR (ID = 2)) OR (ID = 1)) 

ben özyineleme sınırı (100) vuruyorum bu ifadeyi kullanırken, bu yüzden Bu gibi görünen bir ifade oluşturmak istiyorum:

(ID = 5) OR (ID = 4) OR (ID = 3) OR (ID = 2) OR (ID = 1) 

Eski modeli nasıl değiştiririm Bunu yapmak için basma yapı kodu?

cevap

6

: Sadece bir kimlik bazı belirli koleksiyonunda olup olmadığını görmek istiyorsanız gibi, neden bir şey kullanmıyorsanız sol alt ağacın tek bir ifade olduğu ve sağ alt ağacın kalan tüm öğeleri içerdiği OR s dizisi yerine bir parçalanmış ağaç oluşturur. Grafiksel:

Your code    Better 
---------    -------- 
    OR      OR 
#1 OR    OR  OR 
    #2 OR   #1 #2 #3 #4 
     #3 #4 

Gördüğünüz gibi, hatta bu basit durumda daha iyi bir yaklaşım olarak derinden (yinelemeli iç içe) değildir. Daha iyi ifade ağacı oluşturmak için şifre C# bir özyinelemeli yöntem olarak yazılabilir:

Expression GenerateTree(List<Expression> exprs, int start, int end) { 
    // End of the recursive processing - return single element 
    if (start == end) return exprs[start]; 

    // Split the list between two parts of (roughly the same size) 
    var mid = start + (end - start)/2; 
    // Process the two parts recursively and join them using OR 
    var left = GenerateTree(exprs, start, mid); 
    var right = GenerateTree(exprs, mid+1, end); 
    return Expression.Or(left, right); 
} 

// Then call it like this: 
var equalsList = equals.ToList(); 
var body = GenerateTree(equalsList, 0, equalsList.Length); 

Ben kodu deneyin yoktu, bu yüzden bazı küçük hatalar olabilir, ama bu fikri göstermelidir.

+0

Küçük değişiklik - equalsList.Length'u equalsList.Count-1 ile değiştirin - ve mükemmel çalışıyor. Teşekkürler. –

1

Bu, etiketlerinize göre Nesnelerin gerçekten LINQ'iysa, neden ifade ağaçları oluşturuyorsunuz? Delegeleri çok kolay bir şekilde kullanabilir ve tekrarlama sınırına sahip olmayacaklardır. Ancak

, noktaya daha: Bunu çok nesil değiştirmeniz gerekir

var query = from item in source 
      where idCollection.Contains(item.Id) 
      ... 
+0

Özür dilerim, etiketlemem yanlıştı. Yineleme sınırının karşılaşıldığı WCF Data Services kullanıyorum. –

+0

@Ian: WCF Veri Hizmetleri, İçeriği kullanmanıza izin vermiyor mu? Bu hala tercih edilen yaklaşım IMO olacaktı ... –

+0

.NET 3.5'de değil. İçeriği URI sözdizimine dönüştüremez. –