什么时候返回IOrderedEnumerable?

fea*_*net 22 .net c# linq iorderedenumerable semantics

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

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

在存储库用ORDER BY子句包装存储过程的情况下怎么办?存储库应该返回IOrderedEnumerable吗?那将如何实现?

Tho*_*que 19

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

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

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

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

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

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


Jon*_*nna 9

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

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

private static IOrderedEnumerable<int> ReturnOrdered(){return new int[]{1,2,3}.OrderBy(x => x);}
private static IEnumerable<int> ReturnOrderUnknown(){return ReturnOrdered();}//same object, diff return type.
private static void UseEnumerable(IEnumerable<int> col){Console.WriteLine("Unordered");}
private static void UseEnumerable(IOrderedEnumerable<int> col){Console.WriteLine("Ordered");}
private static void ExamineEnumerable(IEnumerable<int> col)
{
  if(col is IOrderedEnumerable<int>)
    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.
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

考虑目前以此结束的方法return currentResults.ToList().以下返回类型是可能的:

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

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

  1. List<T>
  2. IList<T>
  3. ICollection<T>
  4. IEnumerable<T>

列表中的较高位置,我们为调用者提供的便利性使用了该类型公开的功能,而下面的类型没有公开.在我们列表的下方,我们给被调用者更灵活地改变将来的实现.因此,理想情况下,我们希望在方法的目的上下文中尽可能高的列表(向调用者公开有用的功能,并减少创建新集合以提供我们已经提供的功能的情况)但不高(以便将来进行更改).

所以,回到我们的情况IOrderedEnumerable<TElement>,我们可以将其作为一个IOrderedEnumerable<TElement>或一个IEnumerable<T>(或IEnumerableobject)返回.

问题是,这是IOrderedEnumerable与方法的目的本质上相关的事实,还是仅仅是一个实现假象?

如果我们有一个方法ReturnProducts碰巧按价格订购,作为实施删除同一产品两次提供不同价格的情况的一部分,那么它应该返回IEnumerable<Product>,因为来电者不应该关心它的订购,当然不应该'依靠它.

如果我们有一个方法ReturnProductsOrderedByPrice,其中排序是其目的的一部分,那么我们应该返回IOrderedEnumerable<Product>,因为这更接近于它的目的,并且可能合理地期望调用CreateOrderedEnumerable,ThenBy或者ThenByDescending它(它真正提供的唯一的东西)而不是这个由于后续的实施变更而中断.

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

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

在可能的情况下(或许可能IOrderedQueryable<T>),这是一个非常好的主意.但是,这并不简单.

首先,你必须确保在此之后没有任何东西ORDER BY可以撤消订购,这可能不是微不足道的.

其次,你不得在调用时撤消这个顺序CreateOrderedEnumerable<TKey>().

例如,如果与字段元素A,B,CD正在从使用的东西返回ORDER BY A DESCENDING, B导致类型的返回称为MyOrderedEnumerable<El>实现IOrderedEnumerable<El>.然后,事实上,AB是被下令必须存储的字段.到呼叫CreateOrderedEnumerable(e => e.D, Comparer<int>.Default, false)(这也是什么ThenByThenByDescending调入)必须采取同样的对比元素组AB,由他们进行数据库返回相同的规则(匹配数据库和.NET之间的排序规则是很难),只有在那些团体中必须按照顺序排序cmp.Compare(e0.D, e1.D).

如果你能做到这一点,它可能非常有用,并且返回类型是IOrderedEnumerableif ORDER BY条款将出现在所有调用使用的所有查询上是完全合适的.

否则,IOrderedEnumerable这将是一个谎言 - 因为你无法履行它提供的合同 - 而且它将不会无用.