返回“IList”与“ICollection”与“集合”

本文关键字:集合 ICollection IList 返回 | 更新日期: 2023-09-27 18:28:50

我对应该从公共 API 方法和属性返回哪种集合类型感到困惑。

我想到的收藏品是IListICollectionCollection

返回这些类型之一是否总是优于其他类型,还是取决于具体情况?

返回“IList”与“ICollection”与“集合”

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>集合。与其他产品相比,它有两个优点:

  1. 它不允许更改集合(但不允许更改元素,如果它们是引用类型(。

  2. 它允许尽可能多的源,包括通过算法生成且根本不是集合的枚举。

  3. 允许延迟计算,并且可以使用 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>IListIReadOnlyList<T>的实现。

如果使用较窄的接口类型(如 ICollection<T> 而不是 IList<T> (,则可以保护代码免受中断性更改的影响。如果使用更宽的接口类型(如 IList<T> (,则更有可能破坏代码更改。

引用来源,

ICollectionICollection<T> : 您要修改集合或 你关心它的大小。 IListIList<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>,其中OrangeBananaStrawberryFruit的后代。

您的 A.P.I. 用户是否需要泛型类型集合?

使用 List ,其中所有项目都object

干杯。