在LINQ中应用任意数量的OrderBy()



我已经编写了一个扩展方法,可以接受任意数字或OrderBy()并递归地应用它们....

最好还是举个例子:

public static IEnumerable<User> ApplyOrdering(this IEnumerable<User> users,
                                              int index,
                                              params Func<User, string>[] sorts)
{
    if(index == sorts.Length)
        return users;
    users = users.OrderBy(sorts[index]);
    index++;
    return users.ApplyOrdering(index, sorts);
}
// And it's called like this:
void Example()
{
    var users = GetUnsortedUsers();
    var sortedUsers = users.ApplyOrdering(0, u => u.DisplayName,
                                             u => u.Username,
                                             u => u.Email);
}

不是个问题,但我想知道这是否可以用一种更好、更优雅的方式来完成?

首先,我不喜欢在方法调用中声明起始索引。另一个可能的缺点是最后一次调用. applyordering()只是为了返回用户。

你觉得呢?我很想看到你们这些c#大师想出一些聪明的解决方案!

编辑:我知道你们中的一些人会指出,这样写查询更好,更有表现力:
var orderedUsers = users.OrderBy(u => u.DisplayName)
                        .ThenBy(u => u.Username)
                        .ThenBy(u => u.Email);

但是在我的场景中,过滤器的数量和类型并不总是相同的,所以我需要一个通用的解决方案,可以容纳任何数量的过滤器

目前是破碎 -它将有效地应用排序向后。我怀疑你想要:

// Slightly more generic, although it's still requiring projections to string...
public static IEnumerable<T> ApplyOrdering<T>(this IEnumerable<T> source,
                                              params Func<T, string>[] sorts)
{
    // TODO: Argument validation
    if (sorts.Length == 0)
    {
        return source;
    }
    IOrderedEnumerable<T> ordered = source.OrderBy(sorts[0]);
    foreach (var ordering in sorts.Skip(1))
    {
        ordered = ordered.ThenBy(ordering);
    }
    return ordered;
}

您的代码不起作用,您的列表将仅按您设置的最后一个OrderBy排序。

第一个必须使用OrderBy,其他的必须使用ThenBy。

这就是我要做的

public static IEnumerable<User> ApplyOrdering(this IEnumerable<User> users, params Func<User, string>[] sorts) 
{     
    var sorted = users.OrderBy(sorts[0]);
    for(int i = 1; i < sorts.length; i++)
    {
        sorted = sorted.ThenBy(sorts[i]);
    }
    return sorted; 
} 

我没有花时间测试我的代码,我相信有更好的解决方案。

最新更新