什么时候返回IOrderedEnumerable?

IOrderedEnumerable应该IOrderedEnumerable作语义值的返回类型吗?

例如,在表示层中使用模型时,我们如何知道集合是否需要订购或已经订购?

如果存储库使用ORDER BY子句包装存储过程,那该怎么办? 存储库是否应该返回IOrderedEnumerable ? 那将如何实现?

我认为这不是一个好主意:

IOrderedEnumerable应该仅用作语义值的返回类型吗?

例如,在表示层中使用模型时,我们如何知道集合是否需要订购或已经订购?

如果您不知道订购了哪个密钥,那么知道序列是否有序有什么意义呢? IOrderedEnumerable接口的IOrderedEnumerable是能够添加辅助排序标准,如果您不知道主要标准是什么,这没有多大意义。

如果存储库使用ORDER BY子句包装存储过程,那该怎么办? 存储库是否应该返回IOrderedEnumerable? 那将如何实现?

这没有意义。 正如我已经说过的, IOrderedEnumerable用于添加二级排序条件,但是当存储过程返回数据时,它已经被排序,并且添加二级排序条件为时已晚。 你所能做的就是完全重新排序,所以在结果上调用ThenBy将没有预期的效果。

正如托马斯指出的那样,知道一个对象是一个IOrderedEnumerable只告诉我们它是以某种方式订购的,而不是它是以我们想要维护的方式订购的。

值得注意的是,返回类型将影响覆盖和编译能力,但不会影响运行时检查:

 private static IOrderedEnumerable ReturnOrdered(){return new int[]{1,2,3}.OrderBy(x => x);} private static IEnumerable ReturnOrderUnknown(){return ReturnOrdered();}//same object, diff return type. private static void UseEnumerable(IEnumerable col){Console.WriteLine("Unordered");} private static void UseEnumerable(IOrderedEnumerable col){Console.WriteLine("Ordered");} private static void ExamineEnumerable(IEnumerable col) { if(col is IOrderedEnumerable) Console.WriteLine("Enumerable is ordered"); else Console.WriteLine("Enumerable is unordered"); } public static void Main(string[] args) { //Demonstrate compile-time loses info from return types //if variable can take either: var orderUnknown = ReturnOrderUnknown(); UseEnumerable(orderUnknown);//"Unordered"; orderUnknown = ReturnOrdered(); UseEnumerable(orderUnknown);//"Unordered" //Demonstate this wasn't a bug in the overload selection: UseEnumerable(ReturnOrdered());//"Ordered"' //Demonstrate run-time will see "deeper" than the return type anyway: ExamineEnumerable(ReturnOrderUnknown());//Enumerable is ordered. } 

因此,如果您遇到可能有IEnumerableIOrderedEnumerable根据情况返回给调用者的情况,则该变量将被输入为IEnumerable并且返回类型中的信息将丢失。 同时,无论返回类型是什么,调用者都能够确定该类型是否真的是IOrderedEnumerable

无论哪种方式,返回类型并不重要。

与返回类型的权衡是在调用者的实用程序与被调用者的灵活性之间。

考虑一个当前以return currentResults.ToList()结尾的方法。 以下返回类型是可能的:

  1. List
  2. IList
  3. ICollection
  4. IEnumerable
  5. IList
  6. ICollection
  7. IEnumerable
  8. object

让我们现在排除对象和非generics类型不太可能有用(在它们有用的情况下,它们可能是很容易使用的决策)。 这留下:

  1. List
  2. IList
  3. ICollection
  4. IEnumerable

我们列表中的列表越高,我们就越方便地使调用者使用该类型公开的function,而不是下面的类型公开。 我们的列表越低,我们给被调用者更灵活地改变将来的实现。 因此,理想情况下,我们希望在方法的目的上下文中尽可能高的列表(向调用者公开有用的function,并减少创建新集合以提供我们已经提供的function的情况)但不高于(以允许将来的变化)。

所以,回到我们的情况,我们有一个IOrderedEnumerable ,我们可以作为IOrderedEnumerableIEnumerable (或IEnumerableobject )返回。

问题是,这是一个IOrderedEnumerable固有地与方法的目的相关,还是仅仅是一个实现假象?

如果我们有一个方法ReturnProducts碰巧按价格订购,作为删除同一产品两次提供不同价格的情况的实现的一部分,那么它应该返回IEnumerable ,因为调用者不应该关心它的订购,当然不应该依赖它。

如果我们有一个方法ReturnProductsOrderedByPrice ,其中排序是其目的的一部分,那么我们应该返回IOrderedEnumerable ,因为这更接近于它的目的,并且可能合理地期望调用CreateOrderedEnumerableThenByThenByDescending就可以了(唯一的东西)这确实提供了)并且没有通过随后的实施更改而打破这一点。

编辑:我错过了第二部分。

如果存储库使用ORDER BY子句包装存储过程,那该怎么办? 存储库是否应该返回IOrderedEnumerable? 那将如何实现?

在可能的情况下(或者IOrderedQueryable )这是一个非常好的主意。 但是,这并不简单。

首先,您必须确保ORDER BY之后的任何内容都无法撤消排序,这可能并非无足轻重。

其次,您必须在调用CreateOrderedEnumerable()不撤消此排序。

例如,如果从使用ORDER BY A DESCENDING, B返回具有字段ABCD ORDER BY A DESCENDING, B将返回实现IOrderedEnumerable名为MyOrderedEnumerable的类型。 然后,必须存储AB是订购的字段的事实。 对CreateOrderedEnumerable(e => eD, Comparer.Default, false)的调用CreateOrderedEnumerable(e => eD, Comparer.Default, false) (这也是ThenByThenByDescending调用的)必须采用对AB进行相同比较的元素组,它们的规则相同由数据库返回(数据库和.NET之间的匹配排序可能很难),只有在这些组中必须根据cmp.Compare(e0.D, e1.D)

如果你能做到这一点,它可能非常有用,如果所有调用使用的所有查询都存在ORDER BY子句,那么返回类型是IOrderedEnumerable是完全合适的。

否则, IOrderedEnumerable将是一个谎言 – 因为你无法履行它提供的合同 – 而且它将是无用的。