2012-05-02 34 views
32

我有一个关于订单IEnumerable(或IEnumerable<T>,无所谓)的问题。IEnumerable和订单

我们知道,通过IEnumerable的迭代是伪代码可以通过以下方式书写:

while (enumerable.HasNext()) 
{ 
    object obj = enumerable.Current; 
    ... 
} 

现在,假设,一个需要在分类收集操作。在这种情况下可以使用IEnumerable还是使用支持索引的其他方法(即IList)更好?

换句话说:IEnumerable的合同是否对订单作出一般保证?

UPD:因此,IEnumerable不适用于保证排序的通用接口。新的问题是什么接口或类应该用于订单不可变集合? ReadonlyCollectionIList?他们都包含Add()方法(甚至没有在前者实施)。有什么建议?

P.S我自己的想法:IEnumerable不提供任何有关订购的保证。正确的实现可以在不同枚举中以不同顺序返回相同的元素(考虑SQL查询)

P.P.S.我知道LINQ First(),但如果IEnumerable没有说它的排序的话,这个扩展是相当无用的。

回答

25

IEnumerable/IEnumerable<T>对订购不作任何保证,但使用IEnumerable/IEnumerable<T>的实现可能会也可能不会保证排序。

举例来说,如果你列举List<T>,为了得到保证,但如果你列举HashSet<T>没有提供这样的保证,但都将使用IEnumerable<T>接口枚举。

+1

另一个例子是'Dictionary <,>'。它清楚地记录了它的条目枚举的顺序是未定义的。因此,像'dict.Last().Key'这样的代码(其中'dict'是'Dictionary <,>'而'Last()'是LINQ扩展方法)是没有意义的。 (我听说有一位开发人员正在做这件事。) –

+1

我想补充说,它对于正确理解什么是对某些通用集合订单的保证很重要。所以顺序保证不是关于特定的顺序(比如说,作为排序的结果),而是关于保证相同集合的元素的顺序对于随后的枚举是相同的。大多数收集不明确保证。 IList 只代表一种字典,其中键是索引。 –

+0

IOrderedEnumerable可能是一个标志,认为集合保证了顺序(虽然接口仍然没有),但它比我们需要的更多 - 它通常代表一个特定的SORT顺序,而我们需要任何(随机)顺序,这只是在枚举之间保证。总之,只有具体的实现才能真正保证顺序(例如Array,List )。 –

12

实现细节。 IEnumerable将枚举该项目 - 如何实施取决于实施。 MOST列表等按照它们的自然顺序(索引0向上等)运行。

IEnumerable的合同是否保证我们在一般情况下有一定的顺序?

不,它只保证列举(每个项目一次等)。 IEnumerable没有保证顺序,因为它也可用于无序项目。

我知道LINQ First(),但是如果IEnumerable没有对它的顺序说一个字,这个扩展就没用了。

不,它不是,因为你可能有内在的秩序。您以SQL为例 - 结果是一个IEnumerable,但如果我之前强制排序(通过使用OrderBy()),那么IEnumerable将按照LINQ的定义进行排序。 AsEnumerable()。First()通过Order获取我的第一个项目。

4

你可以混合两点:枚举和排序。

当你枚举IEnumerable时,你不应该关心顺序。你使用这个接口,它的实现应该关心顺序。

例如:

void Enumerate(IEnumerable sequence) 
{ 
    // loop 
} 

SortedList<T> sortedList = ... 
Enumerate (sortedList); 

里面,它仍然有固定的顺序列表,但方法不知道具体的接口实现的,它的特点的方法。

6

也许您正在寻找IOrderedEnumerable界面?它由OrderBy()等扩展方法返回,并允许随后使用ThenBy()进行排序。

+0

不幸的是,如果你想接受像IList这样的接口来保证一个订单,但是不会从IOrderedEnumerable继承,那么这将不起作用。请参阅http://stackoverflow.com/q/5429974/1157054 – Ajedi32