27

我遇到了以下代码:

var collection = new Collection<string>();

我没有看到 Collection 类使用太多,也找不到太多关于它的用途的信息。查看 .NET Framework 源代码,它几乎只是一个 List 的包装器,因为它存储了一个 List 成员字段。它的构造函数如下:

public Collection()
{
  this.items = (IList<T>) new List<T>();
}

它还实现了IList。因此,您可以将 Collection 声明为:

IList<string> collection = new Collection<string>();

对我来说,这在功能上等同于创建一个列表:

IList<string> collection = new List<string>();

那么你什么时候想在你自己的代码中在 List 上使用它呢?我看到它是其他 .NET 集合的基类,但为什么它们会将其作为公共具体(而不是内部和/或抽象)包含在内?


关于可能重复的评论——相关问题的答案似乎说 Collection 类应该用作基类。我真正要问的是:

  1. 如果在您自己的代码中使用,为什么不使用 List 作为基类呢?
  2. 在你自己的代码中实例化一个新的 Collection 来代替 List 真的有意义吗?
  3. 如果它真的只是提供作为一个基类,为什么它不是抽象的
4

5 回答 5

18

我认为MSDN 文档本身已经列出了最重要的方面(我强调):

Collection 类提供了受保护的方法,可用于 添加和删除项目、清除集合或设置现有项目的值时自定义其行为。

给实施者的注意事项

提供此基类是为了使实现者更容易创建自定义集合。鼓励实现者扩展这个基类而不是创建自己的基类。

[编辑 ypur 更新问题]

1. 如果在你自己的代码中使用,为什么不使用 List 作为基类呢?

Collection<T>提供了一些受保护的方法,因此您可以轻松地override进行行为并完全注册自己的业务逻辑,例如:

  • ClearItems()
  • InsertItem()
  • RemoveItem()
  • SetItem()

List<T>不提供它们并且几乎没有受保护的方法来覆盖行为,这使得定制变得更加困难。

2. 在你自己的代码中初始化一个新的 Collection 来代替 List 真的有意义吗?

不,不仅仅是为了初始化一些集合。如果您需要它作为实现您自己的逻辑的基类,请使用它。

这将取决于您自己的业务需求。对于日常开发工作中的几乎所有情况,现有的和众多的集合应该已经提供了您需要的东西。有类型安全的和无类型的集合,线程安全的集合,以及任何你能想到的。

尽管如此,有一天可能需要实现一种集合类型,该集合类型在允许添加/更新/删除其中的任何项目之前进行某些验证检查,或者以特殊方式处理移动到仅人口稀少的列表中的下一个项目. 你永远不知道客户可能有什么想法。

在这种情况下,创建自己的集合类型可能会有所帮助。

于 2012-08-22T09:28:41.110 回答
9

Collection(T)类是一大堆其他集合类的基类。List类是为速度优化的类,而 Collection 类是为可扩展性而设计的。

当您查看 的成员时Collection(T),您会发现它包含一些该类没有的其他受保护的虚拟方法(如InsertItem) 。List(T)

事实上,我已经创建了 Collection 类的一个实例。我想我只会将此类型用作方法签名中的参数,只是为了不将方法与集合的实现紧密结合(如果可能的话)。

要回答您的问题:

  1. 我将Collection(T)用作基类,因为该类的意图是用作其他集合类型的基类。它为您提供了更大的灵活性(请参阅受保护的虚拟方法InsertItemRemoveItemSetItem

  2. 当需要一个集合时,我会使用 List(T)该类的一个实例,因为它针对速度进行了优化。

  3. 实际上,我想知道为什么他们没有将Collection(T) 类抽象化。

于 2012-08-22T09:27:10.877 回答
7

正如 Krzysztof Cwalina所说

•List 不是为扩展而设计的。即你不能覆盖任何成员。例如,这意味着从属性返回 List 的对象将无法在修改集合时收到通知。Collection 允许您覆盖 SetItem 受保护的成员,以便在添加新项目或更改现有项目时获得“通知”。

•List 有很多在许多场景中不相关的成员。我们说 List 对于公共对象模型来说太“忙”了。想象一下 ListView.Items 属性返回 List 的所有内容。现在,看看实际的 ListView.Items 返回类型;它更简单,类似于 Collection 或 ReadOnlyCollection。

出于这个原因,FxCop 的规则 CA1002 还告诉您不要公开通用列表,而是使用 Collection。另请参阅此代码分析团队博客文章,了解 FxCop 规则以及为什么返回 Collection 而不是 List。

因此,对于问题 1 和 2,请参见上文。至于问题三,它不仅仅是用作基类。您应该能够实例化它并将其也用作返回类型,因此它不是抽象的。

于 2012-08-24T07:13:56.303 回答
4

我不太喜欢回答自己的问题,但就 Q3 而言,我相信我理解其中的原因。我在查看Bas Paap 的回答中引用的这个链接时得到了它。

简而言之,Collection 类不是抽象的原因是因为您可能希望以后选择从该类派生。同时,您可以将其用作返回类型并直接实例化它。该链接显示了这种情况的代码示例。

我赞成所有其他我认为解决问题中提出的问题的答案。

于 2012-08-24T19:00:27.613 回答
0

尽管枚举接口提供了对集合的只进迭代,但它们不提供确定集合大小、按索引访问成员、搜索或修改集合的机制。对于这样的功能,框架提供了ICollectionIListIDictionary接口。

ICollection<T>提供中等功能(例如Count属性)。

IList<T>并且它们的非通用版本提供了最大的功能(包括按索引的“随机”访问)。

您很少需要实现这些接口中的任何一个。在几乎所有需要编写集合类的情况下,您都可以改为子类Collection<T>等。

我希望这有帮助。

于 2012-08-22T09:42:23.070 回答