How can I use linq to sort by multiple fields?

前端 未结 6 1506
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-29 05:21

I\'m creating a mock data source that I want to be able to pass in a list of SortExpressions on.

public SortExpression(string name, SortDirection direction)
         


        
相关标签:
6条回答
  • 2020-12-29 05:50

    There are two problems. The first is the one others have alluded to - you need to use the value returned by OrderBy etc. The second is that each time you call OrderBy, that's adding a new "primary" ordering. You really want ThenBy after the first ordering has been applied. That makes it pretty ugly, unfortunately. It's still pretty ugly after a refactoring, but not too bad...

    IEnumerable<Data> query = from item in items select item;
    if (sortExpressionsExist)
    {
        // Won't be read in the first iteration; will be written to
        IOrderedEnumerable<Data> orderedQuery = null;
        for (int i = 0; i < sortExpressions.Count; i++)
        {
            // Avoid single variable being captured: capture one per iteration.
            // Evil bug which would be really hard to find :)
            int copyOfI = i;
            // Tailor "object" depending on what GetProperty returns.
            Func<Data, object> expression = item => 
                  item.GetType()
                      .GetProperty(sortExpressions[copyOfI].Name)
                      .GetValue(item, null);
    
            if (sortExpressions[i].Direction == SortDirection.Ascending)
            {
                orderedQuery = (i == 0) ? query.OrderBy(expression)
                                        : orderedQuery.ThenBy(expression);
            }
            else
            {
                orderedQuery = (i == 0) ? query.OrderByDescending(expression)
                                        : orderedQuery.ThenByDescending(expression);
            }
        }
        query = orderedQuery;
    }
    
    0 讨论(0)
  • 2020-12-29 06:00

    The query is not mutable, so OrderBy returns a new object. You need to make the same call, but add "query =" to the beginning.

    query = query.OrderBy(item => item.GetType().GetProperty(sortExpressions[i].Name));
    
    0 讨论(0)
  • 2020-12-29 06:02

    This will work:

    YourCollection.Orderby(item => item.Property1).ThenBy(item => item.Property2);
    
    0 讨论(0)
  • 2020-12-29 06:06

    The OrderBy/OrderByDescending 'operators' work like String.ToUpper(), i.e., they take the thing you invoke it on, and yield a 'copy' that has what you asked for.

    In other words, instead of saying:

    query.Orderby(item->item.X)
    

    you should do

    query = query.Orderby(item->item.X)
    

    or

    sortedResult = query.Orderby(item->item.X)
    

    [And as Jon Skeet points out, use ThenBy/ThenByDescending as in his answer]

    0 讨论(0)
  • 2020-12-29 06:07

    OrderBy on IEnumerable returns returns an IOrderedEnumerable. It does not sort them in line. So get the return value from your .OrderBy and you will be fine.

    0 讨论(0)
  • 2020-12-29 06:15

    OrderBy returns a new IEnumerable, so you need to do something like:

    IEnumerable<Data> results 
        = query.OrderBy(item => item.GetType().GetProperty(sortExpressions[i].Name));
    
    0 讨论(0)
提交回复
热议问题