2011-01-18 26 views
7

Tôi có một bộ sưu tập các đối tượng CLR. Định nghĩa lớp cho đối tượng có ba thuộc tính: FirstName, LastName, BirthDate.Phân loại động với LINQ

Tôi có một chuỗi phản ánh tên của thuộc tính mà bộ sưu tập sẽ được sắp xếp theo. Ngoài ra, tôi có một hướng phân loại. Làm cách nào để tự động áp dụng thông tin sắp xếp này cho bộ sưu tập của tôi? Xin lưu ý rằng việc sắp xếp có thể là nhiều lớp, vì vậy ví dụ tôi có thể sắp xếp theo LastName, và sau đó là FirstName.

Hiện nay, tôi đang cố gắng sau mà không cần bất kỳ may mắn:

var results = myCollection.OrderBy(sortProperty); 

Tuy nhiên, tôi nhận được một thông báo nói rằng:

... không chứa một defintion cho 'OrderBy 'và quá tải phương thức mở rộng tốt nhất ... có một số đối số không hợp lệ.

Trả lời

0

bạn có thể làm điều này với LINQ

var results = from c in myCollection 
    orderby c.SortProperty 
    select c; 
+0

Vấn đề là, sortProperty của tôi là một chuỗi. Làm thế nào tôi có thể làm một loại với một chuỗi như thế? – user564042

+2

ah, tôi hiểu rồi. Tìm thấy một bài đăng khác ở đây có thể giúp ... http://stackoverflow.com/questions/4275878/linq-how-to-dynamically-use-an-order-by-in-linq-but-only-if-a- biến-is-not-st – WraithNath

7

Bạn cần phải xây dựng một Expression Tree và vượt qua nó để OrderBy.
Nó sẽ giống như thế này:

var param = Expression.Parameter(typeof(MyClass)); 
var expression = Expression.Lambda<Func<MyClass, PropertyType>>(
    Expression.Property(param, sortProperty), 
    param 
); 

Ngoài ra, bạn có thể sử dụng Dynamic LINQ, mà sẽ cho phép mã của bạn để làm việc như nó vốn có.

+0

Làm thế nào để xây dựng một cây biểu hiện? – user564042

+0

Cho rằng OP có "một bộ sưu tập các đối tượng CLR" Tôi nghi ngờ anh ta không sau một giải pháp IQueryable. –

+0

@Jon: Vậy thì sao? Bạn vẫn cần một cây biểu thức để sắp xếp động. Điều đó có nghĩa là anh ta sẽ cần gọi là 'Biên dịch'. – SLaks

0

Đối với loại này làm việc năng động Tôi đã sử dụng thư viện động LINQ mà làm cho các loại điều này dễ dàng:

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

http://msdn2.microsoft.com/en-us/vcsharp/bb894665.aspx

+1

'sortProperty' là một chuỗi. – SLaks

+0

Tôi hiểu lầm, tôi đã cập nhật câu trả lời của mình để đề xuất sử dụng thư viện Dynamic Linq. – Peter

0

Đối với động sắp xếp, bạn có thể đánh giá chuỗi tức một cái gì đó như

List<MyObject> foo = new List<MyObject>(); 
string sortProperty = "LastName"; 
var result = foo.OrderBy(x => 
       { 
       if (sortProperty == "LastName") 
        return x.LastName; 
       else 
        return x.FirstName; 
       }); 

Để có giải pháp chung chung hơn, hãy xem chủ đề SO này: Strongly typed dynamic Linq sorting

+0

Rất xấu, và sẽ không hoạt động đối với 'IQueryable'. – SLaks

+0

Đồng ý, nó không phải là một giải pháp rất chung chung, nhưng giải quyết vấn đề này cụ thể – BrokenGlass

0

Bạn sẽ cần phải sử dụng sự phản chiếu để lấy PropertyInfo và sau đó sử dụng để xây dựng một cây biểu thức. Một cái gì đó như thế này:

var entityType = typeof(TEntity); 
var prop = entityType.GetProperty(sortProperty); 
var param = Expression.Parameter(entityType, "x"); 
var access = Expression.Lambda(Expression.MakeMemberAccess(param, prop), param); 

var ordered = (IOrderedQueryable<TEntity>) Queryable.OrderBy(
    myCollection, 
    (dynamic) access); 
10

Được rồi, lập luận của tôi với SLaks trong ý kiến ​​của ông đã buộc tôi phải đưa ra một câu trả lời :)

Tôi giả định rằng bạn chỉ cần hỗ trợ LINQ to Objects.Dưới đây là một số mã mà cần một lượng đáng kể xác nhận thêm, nhưng không làm việc:

// We want the overload which doesn't take an EqualityComparer. 
private static MethodInfo OrderByMethod = typeof(Enumerable) 
    .GetMethods(BindingFlags.Public | BindingFlags.Static) 
    .Where(method => method.Name == "OrderBy" 
      && method.GetParameters().Length == 2) 
    .Single(); 

public static IOrderedEnumerable<TSource> OrderByProperty<TSource>(
    this IEnumerable<TSource> source, 
    string propertyName) 
{ 
    // TODO: Lots of validation :) 
    PropertyInfo property = typeof(TSource).GetProperty(propertyName); 
    MethodInfo getter = property.GetGetMethod(); 
    Type propType = property.PropertyType; 
    Type funcType = typeof(Func<,>).MakeGenericType(typeof(TSource), propType); 
    Delegate func = Delegate.CreateDelegate(funcType, getter); 
    MethodInfo constructedMethod = OrderByMethod.MakeGenericMethod(
     typeof(TSource), propType); 
    return (IOrderedEnumerable<TSource>) constructedMethod.Invoke(null, 
     new object[] { source, func }); 
} 

mã kiểm tra:

string[] foo = new string[] { "Jon", "Holly", "Tom", "William", "Robin" }; 

foreach (string x in foo.OrderByProperty("Length")) 
{ 
    Console.WriteLine(x); 
} 

Output:

Jon 
Tom 
Holly 
Robin 
William 

Nó thậm chí trả về một IOrderedEnumerable<TSource> để bạn có thể chuỗi ThenBy mệnh đề như bình thường :)

+0

Làm thế nào về 'customers.OrderByProperty (" LastName "). Sau đóByProperty (" FirstName ")' hoặc 'customers.OrderByProperty (" LastName "," FirstName ")' (nơi đây là 'params string []'), vì nó có vẻ là một phần của yêu cầu của anh ta. Điều đó có thể thực hiện được trong giải pháp này không? –

+0

@Anthony: Bạn sẽ phải viết thêm mã để làm điều đó tất nhiên, nhưng nó sẽ là có thể - và trông rất giống với đoạn mã trên. –

+0

OK. Và như tôi là một người biết jack squat về chủ đề, có một lý do bạn thích phản ánh hơn việc sử dụng cây biểu thức @SLaks 'không? (Trong trường hợp tôi được trình bày với yêu cầu như vậy trong tương lai.) –

1
protected void sort_grd(object sender, GridViewSortEventArgs e) 
    { 
     if (Convert.ToBoolean(ViewState["order"]) == true) 
     { 
      ViewState["order"] = false; 

     } 
     else 
     { 
      ViewState["order"] = true; 
     } 
     ViewState["SortExp"] = e.SortExpression; 
     dataBind(Convert.ToBoolean(ViewState["order"]), e.SortExpression); 
    } 

public void dataBind(bool ord, string SortExp) 
    { 
     var db = new DataClasses1DataContext(); //linq to sql class 
     var Name = from Ban in db.tbl_Names.AsEnumerable() 
         select new 
         { 
          First_Name = Ban.Banner_Name, 
          Last_Name = Ban.Banner_Project 
         }; 
     if (ord) 
     { 
      Name = BannerName.OrderBy(q => q.GetType().GetProperty(SortExp).GetValue(q, null)); 
     } 
     else 
     { 
      Name = BannerName.OrderByDescending(q => q.GetType().GetProperty(SortExp).GetValue(q, null)); 
     } 
     grdSelectColumn.DataSource = Name ; 
     grdSelectColumn.DataBind(); 
    } 
0

Bạn thực sự có thể sử dụng dòng ban đầu của bạn mã

var results = myCollection.OrderBy(sortProperty); 

đơn giản bằng cách sử dụng thư viện System.Linq.Dynamic.

Nếu bạn nhận được một lỗi biên dịch (cái gì đó như không thể chuyển đổi từ hoặc không chứa một định nghĩa ...), bạn có thể phải làm điều đó như thế này:

var results = myCollection.AsQueryable().OrderBy(sortProperty); 

Không cần bất kỳ cây biểu hiện hoặc dữ liệu ràng buộc.

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