如何使用linq按多个字段排序?

rba*_*all 21 linq

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

public SortExpression(string name, SortDirection direction)
{
     this.name = name;
     this.direction = direction;
}
Run Code Online (Sandbox Code Playgroud)

更新与乔恩斯基特的代码,同时也对整个班级.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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

似乎没有做任何事情.编译,没有错误,只是没有排序.有任何想法吗?

Jon*_*eet 27

有两个问题.第一个是其他人提到的 - 你需要使用返回的值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;
}
Run Code Online (Sandbox Code Playgroud)


Ree*_*sey 5

OrderBy返回一个新的IEnumerable,所以你需要做类似的事情:

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