【问题标题】:How can I use linq to sort by multiple fields?如何使用 linq 按多个字段排序?
【发布时间】:2009-06-05 21:21:56
【问题描述】:

我正在创建一个模拟数据源,希望能够在其上传递一个 SortExpressions 列表。

public SortExpression(string name, SortDirection direction)
{
     this.name = name;
     this.direction = direction;
}

更新 Jon Skeet 的代码以及整个班级。 GetData() 只是用 x 条记录填充对象。

public class Data
{

public int Id { get; set; }
public Guid gId { get; set; }
public string Name { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
public DateTime Created { get; set; }
public string SortMe { get; set; }
public static List<Data> GetFakeData(int start, int numberToFetch, IList<SortExpression> sortExpressions, IList<FilterExpression> filterExpressions, out int totalRecords)
{
    DataCollection items = GetData();
    IEnumerable<Data> query = from item in items select item;

    bool sortExpressionsExist = sortExpressions != null;
    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);

            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;
    }

    bool filterExpressionsExist = filterExpressions != null;
    if (filterExpressionsExist)
    {
        foreach (var filterExpression in filterExpressions)
        {
            query.Where(item => item.GetType().GetProperty(filterExpression.ColumnName).GetValue(item, null).ToString().Contains(filterExpression.Text));
        }
    }
    totalRecords = query.Count();


       return query.Skip(start).Take(numberToFetch).ToList<Data>();
    }
}

似乎什么也没做。编译,没有错误,只是没有排序。有什么想法吗?

【问题讨论】:

    标签: linq


    【解决方案1】:

    有两个问题。第一个是其他人提到的 - 您需要使用 OrderBy 等返回的值。第二个是每次调用 OrderBy 时,都会添加一个新的“主要”排序。在应用第一次订购后,您真的想要ThenBy。不幸的是,这使它非常难看。重构后仍然很丑,但不是糟糕......

    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;
    }
    

    【讨论】:

    • 是的,这就是我使用 for 循环而不是 foreach 的原因,因为我认为我需要在某个地方使用 ThenBy。
    • 顺便说一句,我刚刚修复了一个错误 - 您需要 copyOfI 部分,否则将捕获错误的变量!
    • 是的,得到了​​那个部分。我会刷新看看你是否做了任何进一步的更新。
    • 那么它在做什么呢?完全排序?仅按第一个字段排序?就最后一个?
    • 根本没有排序。和以前一样。
    【解决方案2】:

    OrderBy 返回一个新的 IEnumerable,因此您需要执行以下操作:

    IEnumerable<Data> results 
        = query.OrderBy(item => item.GetType().GetProperty(sortExpressions[i].Name));
    

    【讨论】:

      【解决方案3】:

      OrderBy on IEnumerable 返回一个 IOrderedEnumerable。它不会按顺序对它们进行排序。所以从你的 .OrderBy 获取返回值,你会没事的。

      【讨论】:

        【解决方案4】:

        OrderBy/OrderByDescending“操作符”的工作方式与 String.ToUpper() 类似,即,它们获取您调用它的内容,并生成包含您要求的内容的“副本”。

        换句话说,而不是说:

        query.Orderby(item->item.X)
        

        你应该这样做

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

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

        [正如 Jon Skeet 所指出的,在他的回答中使用ThenBy/ThenByDescending]

        【讨论】:

          【解决方案5】:

          查询不可变,因此 OrderBy 返回一个新对象。您需要进行相同的调用,但在开头添加“query =”。

          query = query.OrderBy(item => item.GetType().GetProperty(sortExpressions[i].Name));
          

          【讨论】:

            【解决方案6】:

            这将起作用:

            YourCollection.Orderby(item => item.Property1).ThenBy(item => item.Property2);
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2014-07-29
              • 2020-11-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-01-06
              • 2021-11-03
              • 2010-09-24
              相关资源
              最近更新 更多