2009-03-03 90 views
6

如何按對象列表中的傳遞字符串值進行排序?我需要在我的List(Of)對象上進行分頁和排序,分頁沒有問題,但我不知道讓Order By工作的是誰。linq排序依據列表(Of myObjects)

以下是我目前做的和它的工作很大:

Return returnReports.Skip(PageSize * (PageNumber-1)).Take(PageSize).ToList() 

我如何得到這個工作?

Return returnReports.OrderBy(SortColumn).Skip(skip).Take(PageSize).ToList() 

SortColumn是一個傳遞的字符串值

回答

11

VB

Module OrderByExtensions 
    <System.Runtime.CompilerServices.Extension()> _ 
    Public Function OrderByPropertyName(Of T)(ByVal e As IEnumerable(Of T), ByVal propertyName As String) As IOrderedEnumerable(Of T) 
    Dim itemType = GetType(T) 
    Dim prop = itemType.GetProperty(propertyName) 
    If prop Is Nothing Then Throw New ArgumentException("Object does not have the specified property") 
    Dim propType = prop.PropertyType 
    Dim funcType = GetType(Func(Of ,)).MakeGenericType(itemType, propType) 
    Dim parameter = Expression.Parameter(itemType, "item") 
    Dim exp = Expression.Lambda(funcType, Expression.MakeMemberAccess(parameter, prop), parameter) 
    Dim params = New Object() {e, exp.Compile()} 
    Return DirectCast(GetType(OrderByExtensions).GetMethod("InvokeOrderBy", Reflection.BindingFlags.Static Or Reflection.BindingFlags.NonPublic).MakeGenericMethod(itemType, propType).Invoke(Nothing, params), IOrderedEnumerable(Of T)) 
    End Function 
    Private Function InvokeOrderBy(Of T, U)(ByVal e As IEnumerable(Of T), ByVal f As Func(Of T, U)) As IOrderedEnumerable(Of T) 
    Return Enumerable.OrderBy(e, f) 
    End Function 
End Module 

C#

public static class OrderByExtensions 
{ 
    public static IOrderedEnumerable<T> OrderByPropertyName<T>(this IEnumerable<T> e, string name) 
    { 
    var itemType = typeof(T); 
    var prop = itemType.GetProperty(name); 
    if (prop == null) throw new ArgumentException("Object does not have the specified property"); 
    var propType = prop.PropertyType; 
    var funcType = typeof(Func<,>).MakeGenericType(itemType, propType); 
    var parameter = Expression.Parameter(itemType, "item"); 
    var memberAccess = Expression.MakeMemberAccess(parameter, prop); 
    var expression = Expression.Lambda(funcType, memberAccess, parameter); 
    var x = typeof(OrderByExtensions).GetMethod("InvokeOrderBy", BindingFlags.Static | BindingFlags.NonPublic); 
    return (IOrderedEnumerable<T>)x.MakeGenericMethod(itemType, propType).Invoke(null, new object[] { e, expression.Compile() }); 
    } 
    static IOrderedEnumerable<T> InvokeOrderBy<T, U>(IEnumerable<T> e, Func<T, U> f) 
    { 
    return e.OrderBy(f); 
    } 
} 
3

傳遞排序列作爲功能。

因此,這將是

public SomeList Foo(Function<Foo, bool> sortFunction, int skip, int PageSize) 
{ 
    return returnReports.OrderBy(sortFunction).Skip(skip).Take(PageSize).ToList(); 
} 

這樣稱呼它

SomeList(f => f.Bar, 5, 10); 
+0

行動委託不返回一個值。 – 2009-03-03 16:14:36

+0

你是對的我會改正的。 – 2009-03-03 16:20:09

1

如果你只是傳遞了一個字符串,你不能這麼做(很容易)。您可以將字符串映射到Func<IEnumerable<Report>, IEnumerable<Report>>,例如(在C#)

// Horrible type. Ick. 
private static readonly 
    Dictionary<string, Func<IEnumerable<Report>,IEnumerable<Report>>> 
    Orderings = 
    new Dictionary<string, Func<IEnumerable<Report>,IEnumerable<Report>>> 
{ 
    { "FirstColumn", (IEnumerable<Report> reports) => 
          reports.OrderBy(report => report.FirstColumn) }, 
    { "SecondColumn", (IEnumerable<Report> reports) => 
          reports.OrderBy(report => report.SecondColumn) }, 

    (etc) 
}; 

然後使用:

// For production usage, include some error checking! 
return Orderings[sortColumn].Skip(skip).Take(pageSize).ToList(); 

如果你能得到SortColumn傳遞作爲適當的Func(可能使你的方法通用),將避免這裏的爛攤子。

2

如果您使用數據庫作爲數據源,那麼您可以使用Dynamic LINQ項目,該項目允許您將Where子句的參數指定爲字符串。

如果您正在使用「Linq to objects」,則需要創建作爲參數動態傳遞的lambda函數。您可以通過使用「Expression.Xyz」方法來構建表達式樹,然後使用將表達式樹轉換爲可用於委託的可調用代理(類型爲Func <>)的「編譯」方法來執行此操作,以便將其用作參數哪裏。如何構建表達式樹的示例可以在another SO thread here中找到。

0

而不是.OrderBy,你可以使用.Sort。只需爲您的對象創建一個Comparer類,如this

public class FooComparer : IComparer<Foo> 
    { 
     private readonly string _sortBy; 
     private readonly bool _sortDesc; 

     public FooComparer(string sortBy) 
     { 
     _sortBy = sortBy.ToLower(); 
     _sortDesc = _sortBy.EndsWith(" desc"); 
     _sortBy = _sortBy.Replace(" asc", string.Empty).Replace(" desc", string.Empty); 
     } 

     //implement IComparer method 
     public int Compare(Foo x, Foo y) 
     { 
     int ret = 0; 

     switch (_sortBy) 
     { 
      //must match lowercase sortname 
      case "date": 
       ret = DateTime.Compare(x.SomeDate, y.SomeDate); 
       break; 
      //other properties you can sort by as above... 

     } 

     //if there is a tie, break it consistently - this will be specific to your object 
     if (ret == 0) 
     { 
      ret = (DateTime.Compare(x.InsertDate, y.InsertDate)); 
     } 

     if (_sortDesc) 
     { 
      ret *= -1; 
     } 

     return ret; 
     } 
    } 

然後排序呼叫將變爲:

Return Foo.Sort(new FooComparer(sortName + " " + sortOrder) 

所以,你將成爲(排序默認爲升序沒有指定當):

returnReports.Sort(new ReturnReportsComparer(SortColumn)); 

return returnReports.Skip(skip).Take(PageSize).ToList()