将 LINQ 订单查询抽象为多级排序函数

Abstracting LINQ order query to multi level sort function

我想制作一个排序扩展方法,它将采用通用集合并使用一个或多个键对其进行排序。键将是集合包含对象的属性。

具有 3 个键的示例 LINQ 查询如下所示。

studentResults.OrderBy(x => x.CG).ThenBy(x => x.Student.Roll)
                                    .ThenBy(x => x.Student.Name).ToList();

我已经找到了可以一键完成的东西。

public static List<TSource> OrderByAsListOrNull<TSource, TKey>(
        this ICollection<TSource> collection, Func<TSource,TKey> keySelector)
    {

        if (collection != null && collection.Count > 0) {
            return collection
                .OrderBy(x => keySelector(x))
                .ToList();
        }
        return null;
    }

我想过使用IEnumerable<Func<TSource, TKey> keySelector>,但我不能那样调用函数。

那么,我该如何实现这种方法呢?

理论上,您可以构建一个 multi-levelled 排序扩展,它区分初始 OrderBy 和随后的 ThenBy 用于二级、三级排序决胜局。由于采用多个订单函数,每个订单函数都可以引用不同的类型,因此您需要软化投影类型(我在下面使用了 object)。

public static class Extensions
{
    public static IEnumerable<T> MyOrderBy<T>(
        this IEnumerable<T> source, 
        params Func<T, object>[] orders)
    {
        Debug.Assert(orders.Length > 0);
        var sortQuery = source.OrderBy(orders[0]);
        foreach(var order in orders.Skip(1))
        {
            sortQuery = sortQuery.ThenBy(order);
        }
        return sortQuery;
    }
}

public class Poco
{
    public string Name {get; set;}
    public int Number {get; set;}
}


void Main()
{
    var items = new []{
        new Poco{Name = "Zebra", Number = 99}, 
        new Poco{Name = "Apple", Number = 123}};

    foreach(var poco in items.MyOrderBy(i => i.Number, i => i.Name))
    {
        Console.WriteLine(poco.Name);
    }
}

此问题(与您的原始函数一样)是您可能希望在某个时候按降序排序。尽管对于数字排序函数,这可以通过传递 *-1 来破解,但对于任意类型

执行此操作将非常困难
// Hack : Order a numeric descending
item => item.Number * -1

对我来说,我会继续使用 Linq 的排序扩展,而不是尝试以任何方式抽象它们!