C# 如何在Linq中的一行代码中对多个属性的列表进行排序

C# 如何在Linq中的一行代码中对多个属性的列表进行排序,c#,linq,sorting,C#,Linq,Sorting,我想对多个属性的列表进行排序。我知道我可以用 List<Order> l = source.OrderBy(c=> c.Property1).ThenBy(c=> c.Property2).ToList(); List l=source.OrderBy(c=>c.Property1).ThenBy(c=>c.Property2.ToList(); 然而,这只是为了提升。若我想对列表进行降序排序,我需要另一个代码 List<Order> l = source

我想对多个属性的列表进行排序。我知道我可以用

List<Order> l = source.OrderBy(c=> c.Property1).ThenBy(c=> c.Property2).ToList();
List l=source.OrderBy(c=>c.Property1).ThenBy(c=>c.Property2.ToList();
然而,这只是为了提升。若我想对列表进行降序排序,我需要另一个代码

List<Order> l = source.OrderByDescending(c=> c.Property1).ThenByDescending(c=> c.Property2).ToList();
listl=source.OrderByDescending(c=>c.Property1)。然后是ByDescending(c=>c.Property2.ToList();
如果我想对属性1进行升序排序,对属性2进行降序排序,我必须使用

List<Order> l = source.OrderBy(c=> c.Property1).ThenByDescending(c=> c.Property2).ToList();
List l=source.OrderBy(c=>c.Property1),然后按降序(c=>c.Property2.ToList();

对于2个属性的排序,我需要4个不同的代码,对于3个属性,我需要9个不同的代码。没有好消息。我想知道是否有一种方法可以在一个代码中进行排序。谢谢

您可以编写自己的LINQ扩展来确定选择哪个方法。例如:

public static class LinqExtensions
{
    public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, bool ascending)
    {
        return ascending ? source.OrderBy(keySelector) : source.OrderByDescending(keySelector);
    }
}
该包提供了一个OrderBy扩展方法,该方法只接受一个字符串:

using System.Linq.Dynamic;
//...    

var l = source.OrderBy("Property1 ascending, Property2 descending").ToList();
您可以使用它动态构建复杂的表达式:

string orderByClause = string.Format("Property1 {0}, Property2 {1}", "ascending", "descending");
var l = source.OrderBy(orderByClause).ToList();

如我在评论中所提到的,请参见项目Wiki中的更多信息,您可以创建如下内容

public static class LinqExtension
{
    public static IOrderedEnumerable<TSource> OrderByAsc<TSource, TKey>(
    this IEnumerable<TSource> source,
    Expression<Func<T, object>> expression)
    {
        IEnumerable<TSource> newEnumerable = source;
        int ctr = 0;
        NewArrayExpression array = expression.Body as NewArrayExpression;
        foreach( object obj in ( IEnumerable<object> )( array.Expressions ) )
        {
             if(ctr == 0)
             newEnumerable = newEnumerable
                .OrderBy(item => item.GetType().GetProperty(obj.ToString()).GetValue(item, null));
             else
             newEnumerable = newEnumerable
                .ThenBy(item => item.GetType().GetProperty(obj.ToString()).GetValue(item, null));
             ctr++;
        }

        return newEnumerable;      
    }

    public static IOrderedEnumerable<TSource> OrderByDesc<TSource, TKey>(
    this IEnumerable<TSource> source,
    Expression<Func<T, object>> expression)
    {
        IEnumerable<TSource> newEnumerable = source;

        NewArrayExpression array = expression.Body as NewArrayExpression;
        int ctr = 0;
        foreach( object obj in ( IEnumerable<object> )( array.Expressions ) )
        {
             if(ctr == 0)
             newEnumerable = newEnumerable
                .OrderByDescending(item => item.GetType().GetProperty(obj.ToString()).GetValue(item, null));
             else
             newEnumerable = newEnumerable
                .ThenByDescending(item => item.GetType().GetProperty(obj.ToString()).GetValue(item, null));
             ctr++;
        }

        return newEnumerable;      
    } 
}
当然,您可以尝试创建一个扩展,将升序和降序合并到一个方法中。只是个主意


免责声明:我在记事本上写了这篇文章,由于缺乏资源,没有对它进行测试。

这是最好的方法……您的意思是希望排序方向参数化吗,因此,相同的代码可以根据参数以升序和降序的任意组合进行排序?我认为linq应该提供一种排序方式,如:OrderBy(c=>c.Property1,sortOrder)。然后是By(c=>c.Property2,sortOrder)。它简单明了。Linq中有类似的东西吗?
对于2个属性的排序,我需要4个不同的代码
-我的意思是,是的,如果你硬编码每个可能的组合。就像从数组中读取100个元素一样,需要100行代码。概括您的需求,然后编写一个小方法,它将决定调用哪个order方法,以及调用哪个属性。@Stuart Whitehouse,是的,我想对参数化的排序,比如OrderBy(c=>c.Property1,sortOrder)。然后by(c=>c.Property2,sortOrder),其中sortOrder是bool。True表示上升,false表示下降。它简单明了。我认为Linq应该有类似的功能。如何做source.OrderBy(a=>a.Id,升序),然后是by(c=>c.name,降序)?我知道对不同属性的排序必须同时进行。@user585440您只需复制上面的代码,然后将其更改为
ThenBy
。但是如何将OrderBy和ThenBy连接起来?@user585440我真的不知道您的意思。您可以使用与上述完全相同的方式编写重载,但要先更改为
,然后再更改为
。然后可以编写
source.OrderBy(a=>a.Id,true),然后编写(a=>a.name,false)
对于
然后按
,源类型为
IOrderedQueryable
public static class LinqExtension
{
    public static IOrderedEnumerable<TSource> OrderByAsc<TSource, TKey>(
    this IEnumerable<TSource> source,
    Expression<Func<T, object>> expression)
    {
        IEnumerable<TSource> newEnumerable = source;
        int ctr = 0;
        NewArrayExpression array = expression.Body as NewArrayExpression;
        foreach( object obj in ( IEnumerable<object> )( array.Expressions ) )
        {
             if(ctr == 0)
             newEnumerable = newEnumerable
                .OrderBy(item => item.GetType().GetProperty(obj.ToString()).GetValue(item, null));
             else
             newEnumerable = newEnumerable
                .ThenBy(item => item.GetType().GetProperty(obj.ToString()).GetValue(item, null));
             ctr++;
        }

        return newEnumerable;      
    }

    public static IOrderedEnumerable<TSource> OrderByDesc<TSource, TKey>(
    this IEnumerable<TSource> source,
    Expression<Func<T, object>> expression)
    {
        IEnumerable<TSource> newEnumerable = source;

        NewArrayExpression array = expression.Body as NewArrayExpression;
        int ctr = 0;
        foreach( object obj in ( IEnumerable<object> )( array.Expressions ) )
        {
             if(ctr == 0)
             newEnumerable = newEnumerable
                .OrderByDescending(item => item.GetType().GetProperty(obj.ToString()).GetValue(item, null));
             else
             newEnumerable = newEnumerable
                .ThenByDescending(item => item.GetType().GetProperty(obj.ToString()).GetValue(item, null));
             ctr++;
        }

        return newEnumerable;      
    } 
}
using myNameSpace.LinqExtensions;
...

l = l.OrderByAsc(item => new [] { item.Prop1, item.Prop2, item.Prop3});
l = l.OrderByDesc(item => new [] { item.Prop1, item.Prop2, item.Prop3});