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

时间:2018-03-11 07:01:55

标签: c# sorting methods extension-methods

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

带有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>,但我无法像这样调用函数。

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

1 个答案:

答案 0 :(得分:3)

理论上,你可以构建一个多级排序扩展,它在初级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的排序扩展中,而不是试图以任何方式抽象它们!