C # 返回’IList’ vs ‘ICollection’ vs ‘Collection’

Returning 'IList' vs 'ICollection' vs 'Collection'

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

我想到的藏品是IListICollectionCollection

返回这些类型中的一个总是比其他类型更受欢迎,还是取决于具体情况?


ICollection是一个公开集合语义的接口,如Add()Remove()Count

CollectionICollection接口的具体实现。

IList本质上是一个具有随机顺序访问的ICollection

在这种情况下,您应该决定您的结果是否需要列表语义,例如基于顺序的索引(然后使用IList),或者您是否只需要返回无序的"包"结果(然后使用ICollection)。


一般来说,您应该返回尽可能通用的类型,即对消费者需要使用的返回数据有足够了解的类型。这样,您就可以更自由地更改API的实现,而不必破坏正在使用它的代码。

还可以考虑将IEnumerable接口作为返回类型。如果只对结果进行迭代,那么消费者不需要更多。


IListICollection的主要区别在于IList允许您通过索引访问元素。IList描述类似数组的类型。ICollection中的元素只能通过枚举访问。两者都允许插入和删除元素。

如果您只需要枚举集合,那么最好使用IEnumerable。它有两个优势:

  • 它不允许对集合进行更改(但不允许对引用对象进行更改,如果这些对象属于引用类型)。

  • 它允许尽可能多的源,包括从算法上生成的、完全不是集合的枚举。

  • Collection是一个基本类,主要对集合的实现者有用。如果您在接口(API)中公开它,那么将排除许多不是从它派生的有用集合。

    IList的一个缺点是数组实现它,但不允许添加或删除项(即不能更改数组长度)。如果在数组上调用IList.Add(item),则会引发异常。由于IList有一个布尔属性IsReadOnly,您可以在尝试执行此操作之前检查该属性,因此情况有所缓解。但在我看来,这仍然是图书馆的设计缺陷。因此,当需要添加或删除项目时,我直接使用List


    IList是所有通用列表的基本接口。因为它是一个有序的集合,所以实现可以决定顺序,从排序顺序到插入顺序不等。此外,Ilist具有item属性,允许方法根据索引读取和编辑列表中的条目。这样就可以在位置索引处插入、删除列表中的值。

    另外,由于IList : ICollectionICollection中的所有方法也可以在这里执行。

    ICollection是所有通用集合的基本接口。它定义大小、枚举器和同步方法。可以在集合中添加或删除项,但由于缺少索引属性,无法选择项在哪个位置发生。

    CollectionIListIlistIReadOnlyList提供了一个实现。

    如果使用更窄的接口类型,如ICollection,而不是IList,则可以保护代码不被破坏。如果使用更广泛的接口类型,如IList,则更容易破坏代码更改。

    从一个来源引用,

    ICollection, ICollection : You want to modify the collection or
    you care about its size.
    IList, IList: You want to modify the collection and you care about the ordering and / or positioning of the elements in the collection.


    返回接口类型更为一般,因此(缺少关于您的特定用例的进一步信息)我倾向于这一点。如果要公开索引支持,请选择IList,否则ICollection就足够了。最后,如果要指示返回的类型是只读的,请选择IEnumerable

    如果你以前没有读过,BradAbrams和KrzysztofCwalina写了一本很棒的书,题为"框架设计指南:可重用.NET库的惯例、习惯用法和模式"(你可以从这里下载摘要)。


    这个问题有一些主题:

    • 接口与类
    • 从几个相似的类、集合、列表、数组中选择哪个特定类?
    • 公共类与子项("泛型")集合

    您可能想强调它是一个面向对象的a.p.i。

    接口与类

    如果您对接口没有太多经验,我建议您坚持使用类。我看到很多时候开发人员都会跳到界面上,即使这不是必须的。

    最后做一个糟糕的界面设计,而不是一个好的类设计,顺便说一下,它最终可以移植到一个好的接口设计中…

    在A.P.I.中你会看到很多接口,但是,不要急着去做,如果你不需要的话。

    您最终将学习如何将接口应用到代码中。

    从几个相似的类、集合、列表、数组中选择哪个特定类?

    C(dotnet)中有几个类可以互换。如前所述,如果您需要一个更具体的类,例如"canBesortedClass",那么在您的a.p.i中明确说明它。

    您的a.p.i.用户真的需要知道,您的类可以被排序,或者对元素应用某种格式吗?然后使用"canbesortedclass"或"elementscanbeipaintedclass",否则使用"GenericBrandClass"。

    否则,使用更一般的类。

    公共集合类与子项("泛型")集合

    你会发现有些类包含其他元素,您可以指定所有元素都应为特定类型。

    泛型集合是可以使用同一集合的类,对于多个代码应用程序,无需创建新集合,对于每个新的子项类型,如:集合。

    您的a.p.i.用户是否需要一个非常特定的类型,所有元素都是相同的?

    使用类似于List的东西。

    您的a.p.i.用户是否需要几个相关类型?

    揭发List给你的a.p.i.,在内部使用ListListList,其中OrangeBananaStrawberryFruit的后代。

    您的a.p.i.用户是否需要泛型类型集合?

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

    干杯。