【问题标题】:Collection<T> class and it's useCollection<T> 类及其用途
【发布时间】:2012-08-17 16:35:42
【问题描述】:

我遇到了以下代码:

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>();

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


关于可能重复的 cmets - 相关问题的答案似乎表明 Collection 类应该用作基类。我真正要问的是:

  1. 如果在您自己的代码中使用,为什么不使用 List 作为基类呢?
  2. 在 用你自己的代码代替 List?
  3. 如果真的只是作为基类提供,为什么不是抽象的

【问题讨论】:

标签: c# .net collections


【解决方案1】:

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

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

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

回答您的问题:

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

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

  3. 实际上,我想知道为什么他们没有制作Collection(T) 类摘要。

【讨论】:

    【解决方案2】:

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

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

    给实施者的注意事项

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

    [编辑 ypur 更新问题]

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

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

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

    List&lt;T&gt; 不提供它们,并且几乎没有保护方法来覆盖行为,这使得自定义变得更加困难。

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

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

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

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

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

    【讨论】:

    • 感谢您的回答...我想知道为什么 Collection 类不是抽象的?
    • @ZaidMasud:这只是一个猜测,但我认为这是为了让您免于实现 核心功能,并让您只专注于实现自己的功能逻辑与基本功能的不同之处
    • 抽象类可以有非抽象的虚方法,所以你说的可以通过抽象类来实现。
    【解决方案3】:

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

    ICollection&lt;T&gt; 提供中等功能(例如Count 属性)。

    IList&lt;T&gt; 及其非通用版本提供了最大的功能(包括按索引的“随机”访问)。

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

    我希望这会有所帮助。

    【讨论】:

      【解决方案4】:

      作为 Krzysztof Cwalina puts it:

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

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

      出于这个原因,FxCop 的规则 CA1002 还告诉您不要公开通用列表,而是使用 Collection。另请参阅此Code Analysis Team Blog post,了解 FxCop 规则以及为什么返回 Collection 而不是 List。

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

      【讨论】:

      • 您的回答对 Q1&2 有意义。对于 Q3,我不遵循您的推理。你不需要实例化一些东西来将它用作返回类型,抽象类可以用作返回类型。
      • 在我阅读了您的代码分析团队博客文章链接后,这篇博客文章实际上为我回答了 Q3(尽管您没有在回答中说明原因)。
      • 就像我说的,您应该能够实例化它并将其用作返回类型。我不确定这与您自己接受的“同时,您可以将其用作返回类型并直接实例化它”的答案有何不同,但是是的。我认为从我链接的博客文章中可以明显看出从中获得的能力。
      【解决方案5】:

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

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

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

      【讨论】:

      • 我仍然不相信第三季度。虽然链接的帖子描绘了一个可行的场景,但我很难称其为令人满意的答案。我的意思是,可以通过公开IList&lt;T&gt; 类型的成员(AFAIK Collection&lt;T&gt; 不会将任何其他成员公开给IList&lt;T&gt; 所需的成员)来轻松解决问题,而Collection&lt;T&gt; 是否抽象将没有意义。虽然在某些时候能够实例化 Collection&lt;T&gt; 可能很方便,但它在某种程度上掩盖了其作为自定义集合基类的主要目的。
      猜你喜欢
      • 2011-06-26
      • 2014-09-09
      • 1970-01-01
      • 2017-09-18
      • 2014-10-17
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 2013-07-06
      相关资源
      最近更新 更多