我对于应该从公共API方法和属性返回哪种集合类型感到困惑。
我心目中的集合是IList
,ICollection
和Collection
。
返回这些类型中的一种总是总是比其他类型更受青睐,还是取决于特定情况?
我对于应该从公共API方法和属性返回哪种集合类型感到困惑。
我心目中的集合是IList
,ICollection
和Collection
。
返回这些类型中的一种总是总是比其他类型更受青睐,还是取决于特定情况?
Answers:
通常,您应该返回一种尽可能通用的类型,即,该类型仅知道使用者需要使用的返回数据。这样,您就拥有更大的自由来更改API的实现,而无需破坏正在使用它的代码。
还可以将IEnumerable<T>
接口视为返回类型。如果结果只是要迭代,那么消费者就不需要更多了。
Count
方法的实现会检查集合的实际类型,因此它将对某些已知类型(例如数组)使用Length
或Count
属性,ICollection
甚至当您将其作为提供时也是如此IEnumerable
。
Thing<T>
实现IList<T>
而不是非泛型ICollection
,则调用IEnumerable<Cat>.Count()
a Thing<Cat>
会很快,但是调用IEnumerable<Animal>.Count()
会很慢(因为扩展方法将查找而不是找到的实现)ICollection<Cat>
)。如果该类实现了非泛型ICollection
,IEnumerable<Animal>.Count
则会找到并使用它。
ICollection<T>
是暴露集合语义诸如接口Add()
,Remove()
和Count
。
Collection<T>
是该ICollection<T>
接口的具体实现。
IList<T>
本质上是ICollection<T>
基于随机订单的访问。
在这种情况下,您应该决定结果是否需要列表语义,例如基于订单的索引(然后使用IList<T>
),或者是否只需要返回无序的结果“袋”(然后使用ICollection<T>
)。
Collection<T>
实现IList<T>
不仅ICollection<T>
。
IEnumerable<T>
是有序的。有什么区别IList<T>
的ICollection<T>
是,它为会员提供与索引工作。例如list[5]
可行,但collection[5]
不会编译。
IList<T>
。有很多没有的有序集合。IList<T>
关于快速索引访问。
IEnumerable<T>
已订购所有收藏品,因为已订购?拿HashSet<T>
-它实现了,IEnumerable<T>
但显然没有命令。也就是说,您对项目的顺序没有任何影响,并且如果内部哈希表已重新组织,则此顺序可以随时更改。
IList<T>
和之间的主要区别ICollection<T>
是,IList<T>
您可以通过索引访问元素。IList<T>
描述类似数组的类型。中的元素ICollection<T>
只能通过枚举访问。两者都允许插入和删除元素。
如果只需要枚举集合,则IEnumerable<T>
是首选。与其他优点相比,它有两个优点:
它不允许更改集合(如果元素是引用类型,则不允许更改)。
它允许尽可能多的来源,包括通过算法生成的枚举,而这些枚举根本不是集合。
Collection<T>
是基类,主要对集合的实现者有用。如果您在接口(API)中公开它,则许多不是从它派生的有用集合将被排除。
缺点之一IList<T>
是数组实现了它,但不允许您添加或删除项(即您不能更改数组长度)。如果调用IList<T>.Add(item)
数组,将引发异常。这种情况有些令人困惑,因为您可以在尝试执行此操作之前先检查IList<T>
其布尔属性IsReadOnly
。但是在我看来,这仍然是库中的设计缺陷。因此,List<T>
当需要添加或删除项目时,我直接使用。
IList<T>
,则无法确保不会将数组作为参数调用该方法。
IList<T>
是所有通用列表的基本接口。由于它是有序集合,因此实现可以决定排序,范围从排序的顺序到插入顺序。而且Ilist
具有Item属性,该属性允许方法根据索引来读取和编辑列表中的条目。这样就可以在位置索引处从列表中插入值或从列表中删除值。
此外,由于IList<T> : ICollection<T>
,ICollection<T>
此处的所有方法也都可用于实现。
ICollection<T>
是所有通用集合的基本接口。它定义了大小,枚举器和同步方法。您可以将项目添加或删除到集合中,但是由于缺少index属性,您无法选择它发生在哪个位置。
Collection<T>
提供了一个实现IList<T>
,IList
和IReadOnlyList<T>
。
如果您使用较窄的接口类型,例如 ICollection<T>
而不是的IList<T>
,则可以保护您的代码以防破坏更改。如果使用更广泛的接口类型(例如)IList<T>
,则更有可能破坏代码更改。
从来源报价,
ICollection
,ICollection<T>
:你想修改的集合或者你关心它的大小。IList
,IList<T>
:你想修改的收集和你关心的集合中的元素的顺序和/或定位。
返回接口类型更为通用,因此(在您的特定用例上缺少更多信息)我倾向于这样做。如果要提供索引支持,请选择IList<T>
,否则ICollection<T>
就足够了。最后,如果要指示返回的类型为只读,请选择IEnumerable<T>
。
而且,如果您以前从未读过它,Brad Abrams和Krzysztof Cwalina写了一本很棒的书,标题为“框架设计准则:可重用.NET库的约定,惯用语和模式”(您可以从此处下载摘要)。
IEnumerable<T>
是只读的?可以,但是即使在执行ToList之后在存储库的上下文中对其进行重新调整也不是线程安全的。问题是原始数据源获取GC时,IEnumarble.ToList()在多线程上下文中不起作用。它工作于线性状态,因为在您完成工作后会调用GC,但async
现在在4.5+的版本中使用IEnumarbale变得越来越痛苦。
这个问题有一些主题:
您可能要强调它是一个面向对象的API
接口与类
如果您对接口没有太多经验,我建议您坚持使用类。我看到很多时候开发人员都跳到了接口,即使它不是必须的。
而且,最终要做一个糟糕的界面设计,而不是一个好的类设计,顺便说一句,最终可以将其移植到一个好的界面设计中。
您会在API中看到很多接口,但是,如果您不需要它,请不要着急。
您最终将学习如何将接口应用于代码。
从几个相似的类,集合,列表,数组中,哪个特定的类?
c#(dotnet)中有几个可以互换的类。如前所述,如果您需要更具体的类中的内容(例如“ CanBeSortedClass”),请在您的API中明确显示。
您的API用户是否真的需要知道,您的类可以排序,还是将某些格式应用于元素?然后使用“ CanBeSortedClass”或“ ElementsCanBePaintedClass”,否则使用“ GenericBrandClass”。
否则,请使用更通用的类。
通用集合类与子项(“泛型”)集合
您会发现有些类包含其他元素,并且可以指定所有元素应为特定类型。
泛型集合是可以为多个代码应用程序使用相同集合的类,而不必为每个新的子项目类型创建新集合,例如:Collection。
您的API用户是否需要一个非常特定的类型,所有元素都一样?
使用类似的东西List<WashingtonApple>
。
您的API用户是否需要几种相关类型?
暴露List<Fruit>
你的API,并使用List<Orange>
List<Banana>
,List<Strawberry>
在内部,在那里Orange
,Banana
并Strawberry
从后代Fruit
。
您的API用户是否需要泛型类型集合?
使用List
,其中所有项目均为object
。
干杯。