简体   繁体   中英

Order a List by a arbitrary sort expression?

Question:

I have a generic list, like this:

System.Collections.Generic.List<Question> myquestions = new System.Collections.Generic.List<Question>();

And I have a paging example, using a LINQ table acquried from database, doing this for paging:

var questions = context.Questions
    .OrderBy(sidx + " " + sord)
    .Skip(pageIndex * pageSize)
    .Take(pageSize);

Right now, for paging my populated from code list, I have:

var questionss = myquestions
    .OrderBy(x => x.Id)
    .Skip(pageIndex * pageSize)
    .Take(pageSize);

And what I want is being able to order "myquestions" by a string as in the above example. Is that possible?

You can chain the extension methods in separate statements thanks to the lazy execution, which means that you can add different sorting depending on a condition:

IOrderedQueryable<Question> sorted;
switch (sort) {
  case "Id":  sorted = myquestions.OrderBy(x => x.Id);
  case "Name": sorted = myquestions.OrderBy(x => x.Name);
  case "Size": sorted = myquestions.OrderBy(x => x.Size);
  case "Id Desc":  sorted = myquestions.OrderByDescending(x => x.Id);
  case "Name Desc": sorted = myquestions.OrderByDescending(x => x.Name);
  case "Size Desc": sorted = myquestions.OrderByDescending(x => x.Size);
  default: throw new NotImplementedException();
}
var questions = sorted.Skip(pageIndex * pageSize).Take(pageSize);

You can even add a secondary sorting (or as many as you like, after the first they are all the same):

IOrderedQueryable<Question> sorted;
switch (sort) {
  case "Id":  sorted = myquestions.OrderBy(x => x.Id);
  case "Name": sorted = myquestions.OrderBy(x => x.Name);
  case "Size": sorted = myquestions.OrderBy(x => x.Size);
  case "Id Desc":  sorted = myquestions.OrderByDescending(x => x.Id);
  case "Name Desc": sorted = myquestions.OrderByDescending(x => x.Name);
  case "Size Desc": sorted = myquestions.OrderByDescending(x => x.Size);
  default: throw new NotImplementedException();
}
switch (sort2) {
  case "Id":  sorted = sorted.ThenBy(x => x.Id);
  case "Name": sorted = sorted.ThenBy(x => x.Name);
  case "Size": sorted = sorted.ThenBy(x => x.Size);
  case "Id Desc":  sorted = sorted.ThenByDescending(x => x.Id);
  case "Name Desc": sorted = sorted.ThenByDescending(x => x.Name);
  case "Size Desc": sorted = sorted.ThenByDescending(x => x.Size);
}
var questions = sorted.Skip(pageIndex * pageSize).Take(pageSize);

请检查我对有关如何使用给定String Expression构建自定义OrderBy谓词的另一个问题的回答

Bahaha, now I'm gonna cry:

Trying to implement dtb's solution, I saw the problem:

OrderByField<T>(IQueryable<T> q,

Returns IQueryable while inputting IQueryable... lol bs. So, the real question is how to convert List to be iQueryable.

Which, in fact is dead simple:

var list = new List<T>(); 
var queryable = list.AsQueryable(); 

then

queryable.OrderBy(sidx + " " + sord);

So the final solution is as trivial as:

myquestions.AsQueryable().OrderBy(sidx + " " + sord).Skip(pageIndex * pageSize).Take(pageSize);

Which also means Linq.Table implements IQueryable, which makes sense IMHO.

Edit:
Note: This requires reference to: Dynamic.dll (not System.Dynamic.dll) as well as

using System.Linq.Dynamic;

If you don't reference Dynamic.dll, or don't declare the using directive, you'll get an error on AsQueryable().

One option is to create a dictionary from each possible ordering string to an appropriate delegate. For example:

Dictionary<string, Func<IEnumerable<Question>, IEnumerable<Question>> orderings =
    new Dictionary<string, Func<IEnumerable<Question>, IEnumerable<Question>>()
{
    { "Id",  questions => questions.OrderBy(x => x.Id) },
    { "Title",  questions => questions.OrderBy(x => x.Title) },
    { "Answer",  questions => questions.OrderBy(x => x.Answer) },
    { "Id Desc",  questions => questions.OrderByDescending(x => x.Id) },
    { "Title Desc",  questions => questions.OrderByDescending(x => x.Title) },
    { "Answer Desc",  questions => questions.OrderByDescending(x => x.Answer) },
};

Then you can find that mapping at execution time, and apply the function.

You could look at Dynamic Linq . IIRC it was a sample that shipped with VS2008, I'm not 100% sure if it's still included in VS2010.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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