2010-05-30 52 views
5

Tôi đang sử dụng một số mã (có sẵn here trên MSDN) để tự động xây dựng các biểu thức LINQ chứa nhiều OR 'mệnh đề'.Xây dựng 'phẳng' thay vì 'cây' biểu thức LINQ

Mã liên quan là

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)); 

này tạo ra một biểu thức LINQ mà trông giống như sau:

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

Tôi đánh giới hạn đệ quy (100) khi sử dụng cụm từ này, vì vậy tôi muốn tạo biểu thức giống như sau:

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

Làm cách nào để sửa đổi ví dụ cũ pression xây dựng mã để làm điều này?

Trả lời

6

Bạn cần phải sửa đổi hệ để nó xây dựng một cây ballanced thay vì một dãy gồm OR s nơi cây con bên trái là một biểu thức duy nhất và cây con bên phải chứa tất cả các phần tử còn lại. Đồ họa:

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

Như bạn có thể thấy, ngay cả trong trường hợp đơn giản này, cách tiếp cận tốt hơn không sâu (lồng nhau đệ quy). Mã để tạo cây biểu thức tốt hơn có thể được viết dưới dạng phương thức đệ quy trong C#:

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); 

Tôi không thử mã, vì vậy có thể có một số lỗi nhỏ, nhưng nó sẽ hiển thị ý tưởng.

+0

Thay đổi nhỏ - thay thế equalsList.Length bằng equalsList.Count-1 - và nó hoạt động hoàn hảo. Cảm ơn. –

1

Nếu điều này thực sự là LINQ to Objects theo thẻ của bạn, tại sao bạn lại xây dựng cây biểu thức? Bạn có thể sử dụng các đại biểu rất dễ dàng và họ sẽ không có giới hạn đệ quy.

Tuy nhiên, nhiều đến mức: nếu bạn chỉ muốn xem một ID là trong một số bộ sưu tập đặc biệt, tại sao bạn không sử dụng một cái gì đó như:

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

Xin lỗi, việc gắn thẻ của tôi không chính xác. Tôi đang sử dụng dịch vụ dữ liệu WCF, đó là nơi giới hạn đệ quy đang được gặp phải. –

+0

@Ian: Dịch vụ dữ liệu WCF có cho phép bạn sử dụng Chứa không? Đó vẫn sẽ là cách tiếp cận ưa thích IMO ... –

+0

Nó không có trong .NET 3.5. Nó không thể chuyển đổi Chứa vào cú pháp URI. –

Các vấn đề liên quan