遵循a public APIs should never return a list的规则,我正在盲目转换所有返回列表的代码,而是返回ICollection<T>
:
public IList<T> CommaSeparate(String value) {...}
变为
public ICollection<T> CommaSeparate(String value) {...}
虽然ICollection
有Count
,但无法通过该索引获取项目。
虽然ICollection
公开了一个枚举器(允许foreach
),但我不能保证枚举的顺序从列表的“顶部”开始,而不是“底部”。
我可以通过避免使用ICollection
来缓解这种情况,而是使用Collection
:
public Collection<T> Commaseparate(String value) {...}
这允许使用Items[index]
语法。
不幸的是,我的内部实现构造了一个数组;我可以强制转换为IList
或ICollection
,而不是Collection
。
是否有办法按顺序访问集合的项目??
这引出了一个更广泛的问题: ICollection 甚至是否有订单?
从概念上讲, 想象 我想解析一个命令行字符串。保持物品的顺序至关重要。
从概念上讲,我需要一个表示“有序”字符串元组集的契约。在API合同的情况下,为了表明订单,以下哪项是正确的:
IEnumerable<String> Grob(string s)
ICollection<String> Grob(string s)
IList<String> Grob(string s)
Collection<String> Grob(string s)
List<String> Grob(string s)
答案 0 :(得分:15)
ICollection<T>
界面未指定任何有关订单的内容。对象将按返回的对象指定的顺序排列。例如,如果您返回Values
的{{1}}集合,则对象将按照字典的比较器定义的顺序。
如果您需要通过合同返回合同需要某个订单的类型的方法,那么您应该通过返回更具体的类型在方法的签名中表示。
无论返回的对象的运行时类型如何,请考虑静态引用为SortedDictionary
或IList<T>
时的行为:当您调用ICollection<T>
时(可能隐含在foreach循环中),无论引用的静态类型如何,您都将调用相同的方法并获取相同的对象。因此,无论GetEnumerator()
方法的返回类型如何,它都会以相同的方式运行。
补充思想:
正如其他人指出的那样,FXCop规则警告不要使用CommaSeparate()
,而不是List<T>
;您链接的问题是询问为什么FXCop不建议使用IList<T>
代替IList<T>
,这是另一回事。如果我想你正在解析一个命令行字符串,其中顺序很重要,如果我是你,我会坚持使用List<T>
。
答案 1 :(得分:9)
ICollection没有保证订单,但实际实现它的类可能(或可能不)。
如果你想要返回一个有序的集合,那么返回一个IList<T>
并且不要太依赖FxCop通常合理但非常通用的建议。
答案 2 :(得分:4)
不,ICollection并不意味着订单。
答案 3 :(得分:3)
ICollection
实例具有实现它的任何类的“顺序”。也就是说,将List<T>
引用为ICollection
根本不会改变其顺序。
同样,如果您将无序集合作为ICollection
访问,它也不会对无序集合强加订单。
那么,对你的问题:
ICollection是否有订单?
答案是:它完全取决于实现它的类。
答案 4 :(得分:3)
ICollection
只是一个接口 - 没有关于排序的实现或明确规范。这意味着如果您以有序的方式返回枚举的内容,那么消费的ICollection
将以有序的方式进行。
订单仅由底层的实施对象隐含。 ICollection
中没有说明应该订购的规范。多次枚举结果将调用底层对象的枚举器,这是唯一可以设置这些规则的位置。对象不会因为它继承此接口而更改枚举方式。如果接口指定它是一个有序的结果,那么你可以放心地依赖于实现对象的有序结果。
答案 5 :(得分:3)
ICollection<T>
可能有一个订单,但实际的排序取决于实现它的类。
它没有给定索引处的项的访问者。 IList<T>
专门用于通过索引提供访问权限。
答案 6 :(得分:2)
ICollection<T>
只是一个界面;它是否有序完全依赖于它下面的实现(它应该是不透明的)。
如果您希望能够通过索引访问它,则需要将内容返回IList<T>
,即IEnumerable<T>
和ICollection<T>
。但是,应该记住,根据底层实现,获取集合中的任意项目可能需要平均O(N / 2)次。
我倾向于完全避免使用'collection'接口,而是使用代表集合的自定义类型来解决问题域并公开适合该类型的适当逻辑操作。
答案 7 :(得分:1)
这取决于实例的实现。碰巧是List的ICollection有一个订单,恰好是Collection的ICollection没有。
所有ICollections都实现IEnumerable,它一次返回一个项目,无论是有序还是其他方式。
编辑:在回答关于问题中命令行解析的其他示例时,我认为适当的返回类型取决于您之后对这些参数的处理,但IEnumerable可能是正确的。我的理由是IList,ICollection及其具体实现允许修改从Grob返回的列表,这可能是您不想要的。由于.NET没有索引序列接口,IEnumerable是阻止你的调用者做一些奇怪的事情的最佳选择,比如试图修改他们回来的参数列表。
答案 8 :(得分:-1)
如果您希望方法的所有当前版本和将来版本都能轻松返回一个能够快速轻松地检索第N个项目的对象,请使用类型IList<T>
返回对实现的内容的引用IList<T>
和非通用ICollection
。如果您希望某些现有版本或未来版本可能无法快速轻松地返回第N个项目,但能够立即报告项目数量,请使用类型ICollection<T>
返回实现ICollection<T>
的引用1}}和非通用ICollection
。如果您希望现在或将来的版本可能无法知道有多少项目,请返回IEnumerable<T>
。排序问题无关紧要;访问第N个事物的能力意味着存在已定义的序列,但ICollection<T>
对序列的描述和IEnumerable<T>
都没有。