简体   繁体   English

如何根据用户输入在LINQ中进行OrderBy和ThenBy?

[英]How do I OrderBy and ThenBy in LINQ based on user input?

I have a grid on a page which I want to be sortable on multiple columns at the same time. 我在页面上有一个网格,希望同时可以对多列进行排序。

For example: 例如:

UserID        FirstName        LastName
=======================================
1             Bruce            Wayne
2             Peter            Parker
3             Clark            Kent
4             Tony             Stark
5             Helena           Wayne

The user can choose to order by LastName ASC then by FirstName DESC, which would produce the following: 用户可以选择按姓氏ASC然后按名字DESC订购,这将产生以下结果:

UserID        FirstName        LastName
=======================================
3             Clark            Kent
2             Peter            Parker
4             Tony             Stark
5             Helena           Wayne
1             Bruce            Wayne

The user could reset the ordering and decide to order it in some other fashion. 用户可以重置订购并决定以其他方式订购。

How can I achieve this in LINQ? 如何在LINQ中实现这一目标? As far as I know, the way to chain ordering is to do something like 据我所知,连锁订购的方式是做类似

superheroes.OrderBy(x => x.LastName).ThenByDescending(x => x.FirstName)

Obviously, I don't want to have to write out every possible combination of column orders (my grid may have up to 10 columns). 显然,我不想写出列顺序的所有可能组合(我的网格最多可以有10列)。 Is there some way to make the ordering sequence dynamic? 有什么方法可以使订购顺序动态化吗?

A naive approach for IEnumerable (not perfect or tested, but you get the idea). IEnumerable的幼稚方法(虽然不是完美的或经过测试的,但您可以理解)。 I've put the switch on the outside so the comparison is done only once, not for each time the selector is called. 我将开关放在外面,这样比较仅进行一次,而不是每次选择器都被调用。 A little ugly because you essentially have to repeat yourself in OrderBy and ThenBy, though. 有点难看,因为您本质上必须在OrderBy和ThenBy中重复自己。

enum OrderableColumns {UserID, FirstName, ...}

IOrderedEnumerable<SuperHero> OrderBy(SuperHeroes superheroes, OrderableColumns column)
{
    switch(column)
    {
        case UserID:
            return superheroes.OrderBy(x => x.UserID);
        case FirstName:
            return superheroes.OrderBy(x => x.FirstName);
        ...
    }
}

IOrderedEnumerable<SuperHero> ThenBy(IOrderedEnumerable<SuperHero> superheroes, OrderableColumns column)
{
    switch(column)
    {
        case UserID:
            return superheroes.ThenBy(x => x.UserID);
        case FirstName:
            return superheroes.ThenBy(x => x.FirstName);
        ...
    }
}

IOrderedEnumerable<SuperHero> OrderSuperheroes(SuperHeroes superheroes, params OrderableColumns[] columns)
{
     var ordered = OrderBy(superheroes, columns[0]);

     foreach(var col in columns.Skip(1))
         ordered = ThenBy(ordered, col);

     return ordered;
}

You need to use dynamic LINQ. 您需要使用动态LINQ。 Have a look at Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library) 看看动态LINQ(第1部分:使用LINQ动态查询库)

You can build an Func<T,TResult> Dynamic, like this: 您可以构建Func<T,TResult> Dynamic,如下所示:

public static Func<T,object> GetExp<T>(string preportyName)
{
    var instance = Expression.Parameter(typeof(T));
    var callPreporty = Expression.PropertyOrField(instance, preportyName);
    var lambda = Expression.Lambda<Func<T, object>>(callPreporty,instance);
    return lambda.Compile();
}

Use like this: 像这样使用:

var pdotName = GetExp<Person>("Name");  //equals: p=>p.Name
var pdotID = GetExp<Person>("Id");  ////equals: p=>p.Id
var ordered = list.OrderBy(pdotName).ThenBy(pdotID);
//equals: list.OrderBy(p=>p.Name).ThenBy(p=>p.Id)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM