返回“IList”与“ICollection”与“集合”
本文关键字:集合 ICollection IList 返回 | 更新日期: 2023-09-27 18:28:50
我对应该从公共 API 方法和属性返回哪种集合类型感到困惑。
我想到的收藏品是IList
、ICollection
和Collection
。
返回这些类型之一是否总是优于其他类型,还是取决于具体情况?
ICollection<T>
是一个公开集合语义(如 Add()
、Remove()
和 Count
(的接口。
Collection<T>
是ICollection<T>
接口的具体实现。
IList<T>
本质上是一个具有随机顺序访问的ICollection<T>
。
在这种情况下,您应该决定您的结果是否需要列表语义,例如基于顺序的索引(然后使用 IList<T>
(,或者您是否只需要返回一个无序的结果"袋"(然后使用 ICollection<T>
(。
您应该返回一个尽可能通用的类型,即一个只知道使用者需要使用的返回数据的类型。这样,您就可以更自由地更改 API 的实现,而不会破坏使用它的代码。
还将IEnumerable<T>
接口视为返回类型。如果结果只是迭代,则消费者不需要更多。
IList<T>
接口和ICollection<T>
接口之间的主要区别在于IList<T>
允许您通过索引访问元素。 IList<T>
描述了类似数组的类型。ICollection<T>
中的元素只能通过枚举进行访问。两者都允许插入和删除元素。
如果只需要枚举集合,则首选IEnumerable<T>
集合。与其他产品相比,它有两个优点:
-
它不允许更改集合(但不允许更改元素,如果它们是引用类型(。
-
它允许尽可能多的源,包括通过算法生成且根本不是集合的枚举。
-
允许延迟计算,并且可以使用 LINQ 进行查询。
Collection<T>
是一个基类,主要对集合的实现者有用。如果在接口 (API( 中公开它,则将排除许多不是从它派生的有用集合。
IList<T>
的一个缺点是数组实现了它,但不允许您添加或删除项目(即您无法更改数组长度(。如果在数组上调用IList<T>.Add(item)
,则会引发异常。这种情况有所缓解,因为IList<T>
有一个布尔属性IsReadOnly
,您可以在尝试这样做之前进行检查。但在我眼里,这仍然是图书馆的设计缺陷。因此,当需要添加或删除项目的可能性时,我直接使用List<T>
。
我应该选择哪一个?让我们仅考虑List<T>
和IEnumerable<T>
作为专用/广义类型的示例:
- 方法输入参数
-
IEnumerable<T>
呼叫者的最大灵活性。对实施者有限制,只读。 -
List<T>
对调用方有限制。为实现者提供灵活性,可以操作集合。
-
- 方法输出参数或返回值
-
IEnumerable<T>
对调用方限制,只读。为实施者提供最大的灵活性。允许返回任何集合或实现迭代器 (yield return
(。 -
List<T>
调用方的最大灵活性,可以操作返回的集合。对实施者有限制。
-
好吧,在这一点上,你可能会感到失望,因为我没有给你一个简单的答案。像"始终将这个用于输入和那个用于输出">这样的语句不会是建设性的。现实情况是,这取决于用例。像void AddMissingEntries(TColl collection)
这样的方法必须提供具有Add
方法的集合类型,甚至可能需要HashSet<T>
以提高效率。一种void PrintItems(TColl collection)
可以与IEnumerable<T>
幸福生活的方法。
IList<T>
是所有泛型列表的基本接口。由于它是一个有序集合,因此实现可以决定排序,范围从排序顺序到广告顺序。此外,Ilist
具有 Item 属性,该属性允许方法根据索引读取和编辑列表中的条目。这样就可以在位置索引的列表中插入、删除值。
同样从IList<T> : ICollection<T>
开始,ICollection<T>
的所有方法也可以在这里实现。
ICollection<T>
是所有泛型集合的基本接口。它定义大小、枚举器和同步方法。可以在集合中添加或删除项,但由于缺少索引属性,因此无法选择该项所在的位置。
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库的约定,习惯用法和模式"(你可以从这里下载摘要(。
这个问题有一些主题:
- 接口与类
- 哪个特定的类,来自几个相似的类,集合,列表,数组?
- 公共类与子项("泛型"(集合
你可能想强调它是一个面向对象的A.P.I。
接口与类
如果你对接口没有太多经验,我建议你坚持上课。我看到很多时候开发人员跳到界面,即使它不是必需的。
并且,结束做一个糟糕的界面设计,而不是一个好的类设计,顺便说一下,它最终可以迁移到一个好的界面设计......
你会在 A.P.I. 中看到很多接口,但是,不要急于求成,如果你不需要它。
您最终将学习如何将接口应用于代码。
哪个特定的类,来自几个相似的类,集合,列表,数组?
C# (dotnet( 中有几个类可以互换。如前所述,如果您需要来自更具体类的内容,例如"CanBeSortedClass",请在您的 API 中明确说明。
您的A.P.I. 用户是否真的需要知道您的类可以排序,或者对元素应用某种格式?然后使用"CanBeSortedClass"或"ElementsCanBePaintedClass",否则使用"通用品牌类"。
否则,请使用更通用的类。
常见集合类与子项("泛型"(集合
你会发现有些类包含其他元素,您可以指定所有元素都应属于特定类型。
泛型集合是那些您可以使用同一集合的类,对于多个代码应用程序,无需创建新集合,对于每个新的子项类型,如下所示:集合。
您的 A.P.I. 用户是否需要一个非常特定的类型,对所有元素都相同?
使用类似 List<WashingtonApple>
.
您的 API 用户是否需要几种相关类型?
公开 API 的List<Fruit>
,并在内部使用List<Orange>
List<Banana>
,List<Strawberry>
,其中Orange
、Banana
和Strawberry
是Fruit
的后代。
您的 A.P.I. 用户是否需要泛型类型集合?
使用 List
,其中所有项目都object
。
干杯。