使用LINQ进行动态排序

use*_*042 7 linq

我有一组CLR对象.该对象的类定义有三个属性:FirstName,LastName,BirthDate.

我有一个字符串,反映了集合应该排序的属性的名称.另外,我有一个排序方向.如何将此排序信息动态应用于我的收藏?请注意,排序可以是多层的,因此我可以按LastName排序,然后按FirstName排序.

目前,我正在尝试以下运气:

var results = myCollection.OrderBy(sortProperty);
Run Code Online (Sandbox Code Playgroud)

但是,我收到的消息是:

...不包含'OrderBy'的定义,并且最好的扩展方法重载......有一些无效的参数.

Jon*_*eet 10

好吧,我在他的评论中与SLaks的争论迫使我想出一个答案:)

我假设你只需要支持LINQ to Objects.这里有一些代码需要大量的验证添加,但确实有效:

// 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 });
}
Run Code Online (Sandbox Code Playgroud)

测试代码:

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

foreach (string x in foo.OrderByProperty("Length"))
{
    Console.WriteLine(x);
}
Run Code Online (Sandbox Code Playgroud)

输出:

Jon
Tom
Holly
Robin
William
Run Code Online (Sandbox Code Playgroud)

它甚至返回一个IOrderedEnumerable<TSource>所以你可以ThenBy正常链接条款:)


SLa*_*aks 7

您需要构建表达式树并将其传递给OrderBy.
它看起来像这样:

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

或者,您可以使用Dynamic LINQ,它将允许您的代码按原样工作.


Wra*_*ath 0

你可以用 Linq 来做到这一点

var results = from c in myCollection
    orderby c.SortProperty
    select c;
Run Code Online (Sandbox Code Playgroud)

  • 啊,我明白了。在这里找到另一篇文章可能会有所帮助... http://stackoverflow.com/questions/4275878/linq-how-to-dynamically-use-an-order-by-in-linq-but-only-if-a-变量不是st (2认同)