在List<T>上自定义OrderBy

29

我正在尝试找出最佳的方法来自定义排序List。假设T是一个具有日期(DateTime?)属性和状态(string)属性的对象。

我有3种情况...

"紧急": 我想把这些放在列表的顶部,没有特定的顺序
日期 = null
状态 = "紧急"

"普通": 我希望在紧急情况之后按日期排序
日期 = 任何有效的日期/时间
状态 = "准时"

"稍后": 我想把这些放在列表的底部,没有特定的顺序
日期 = null
状态 = "稍后"

有什么想法吗?我应该使用IQuerable对象而不是List吗?我可以随时将对象转换为.ToList()以发送到我的视图。


1
根据我的理解,通过实现IComparable接口来处理排序是对象的职责。 - Spidy
这是使用表达式的另一种方式 https://dev59.com/LUvSa4cB1Zd3GeqPcCnS#56868434 - Tiju John
5个回答

70
query = query.OrderBy(x =>
  x.Status == "Urgent" ? 1:
  x.Status == "Normal" ? 2:
  3)
  .ThenBy(x => 
  x.Status == "Urgent" ? null:
  x.Status == "Normal" ? x.Date:
  null);

随意思考:Ordering(排序)属于查询还是类?


16

这应该不太难,只需要让T实现您的比较规则,使用IComparable接口,就可以完成设置。


我还在摸索这个。这会将.OrderBy()从中排除,对吗?如果我选择这条路线,现在会调用list.Sort()。这样以后的读者就清楚了。 - BZink
1
@BZink嗯,你也应该能够执行... myCollection.OrderBy(o => o);,它将使用对象的默认比较器对对象进行排序,该比较器应该是您实现的IComparable接口,但我不认为使用它比使用Sort()方法有任何优势。 - Quintin Robinson

2

你可以使用扩展方法:

像这样...

public static IOrderedEmumerable<MyType> OrderForDisplay (this IEnumerable<MyType> input)
{
  return
    input
    .OrderBy(item => item.Status)
    .ThenByDescending(item => item.Status == 1 ? DateTime.MaxDate : item.date);
}

为什么要为这样的事情实现自己的扩展方法?有更好的方法,请参见其他答案。 - Daniel Hilgarth
因为它可以在代码的其他地方重复使用(如果需要),并且可以使其具有一致的排序。var MyItemsToDisplay = MyList.OrderForDisplay();(等等...) - DaveShaw
状态是以字符串形式存在的,因此按排序顺序会导致与请求的顺序不同。只有普通项目应按日期排序,而您的代码无法编译,因为没有方法名称。 - Rune FS
实现 IComparable 可以达到相同的目标,但有一个标准的方法来完成它。 - Daniel Hilgarth

2

您需要提供一个IComparer的实现,然后可以使用以下重载将其传递:

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector,
    IComparer<TKey> comparer
)

参见:http://msdn.microsoft.com/zh-cn/library/bb549422.aspx


2

我认为最简单的方法是使用linq:

itemsList = itemsList.OrderByDescending(ob => ob.status ).ThenBy(ob => ob.date).ToList();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接