对于默认情况,您需要做的就是:
queryRes = values.OrderBy(a => 1);
这实际上是一个 noop 排序。因为 OrderBy 执行稳定的排序,所以在所选对象相等的情况下将保持原始顺序。请注意,由于这是一个IQueryable
而不是一个IEnumerable
,因此查询提供程序可能无法执行稳定的排序。在这种情况下,您需要知道保持顺序是否重要,或者是否适合只说“我不在乎结果是什么顺序,只要我可以调用ThenBy
结果即可)。
另一个允许您避免实际排序的选项是创建自己的IOrderedEnumerable
实现:
public class NoopOrder<T> : IOrderedEnumerable<T>
{
private IQueryable<T> source;
public NoopOrder(IQueryable<T> source)
{
this.source = source;
}
public IOrderedEnumerable<T> CreateOrderedEnumerable<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer, bool descending)
{
if (descending)
{
return source.OrderByDescending(keySelector, comparer);
}
else
{
return source.OrderBy(keySelector, comparer);
}
}
public IEnumerator<T> GetEnumerator()
{
return source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return source.GetEnumerator();
}
}
这样您的查询可以是:
queryRes = new NoopOrder<AClass>(values);
请注意,上述类的结果是,如果调用该类ThenBy
将ThenBy
有效地进行顶级排序。它实际上是把后续ThenBy
变成了一个OrderBy
电话。(这应该不足为奇;ThenBy
将调用该CreateOrderedEnumerable
方法,并且在其中此代码正在调用OrderBy
,基本上将其ThenBy
转换为OrderBy
。从概念排序的角度来看,这是一种说法,即“此序列中的所有项目都是在这种人眼中是相等的,但是如果您指定相等的对象应该被其他东西打破,那么就这样做。
“无操作排序”的另一种思考方式是它根据输入序列的索引对项目进行排序。这意味着项目并非全部“相等”,这意味着订单输入序列将是输出序列的最终订单,并且由于输入序列中的每个项目总是大于它之前的项目,因此添加了额外的“tiebreaker” " 比较将无济于事,使任何后续ThenBy
调用都毫无意义。如果需要这种行为,它甚至比前一种更容易实现:
public class NoopOrder<T> : IOrderedEnumerable<T>
{
private IQueryable<T> source;
public NoopOrder(IQueryable<T> source)
{
this.source = source;
}
public IOrderedEnumerable<T> CreateOrderedEnumerable<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer, bool descending)
{
return new NoopOrder<T>(source);
}
public IEnumerator<T> GetEnumerator()
{
return source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return source.GetEnumerator();
}
}