【问题标题】:Why does ICollection not contain an Add method? [closed]为什么 ICollection 不包含 Add 方法? [关闭]
【发布时间】:2012-07-26 06:29:18
【问题描述】:

如标题所示,有谁知道为什么ICollection 接口不包含Add 方法?通用版本ICollection<T> 有一个AddICollection 没有,这似乎很奇怪。任何对此有更深入了解的人都会非常有帮助。

至于我为什么关心 - 不幸的是,构建 SharePoint 的开发人员从未了解过泛型,因此 API 中的每个集合都是基于 ICollection 的非泛型集合。我想将几个扩展方法附加到 ICollection,其中包括添加到集合中,但这似乎是不可能的(至少在没有反射的情况下是不可能的)。

编辑:

很多人在推测原因是因为ICollection.Add 需要Object,因此不会是类型安全的。事实并非如此。 IList 一个 Add 方法,它采用 Object。您只需在采用 Object 的方法中进行类型检查和强制转换。

数组实现ICollection,因此它不能有Add 的论点也不成立。如果ICollection 有一个Add 方法,它只需要在数组上显式实现并抛出一个异常(就像数组当前实现的许多方法一样)。

我真的希望有人参考其中一位设计师的解释。

【问题讨论】:

  • @MicahArmantrout,他说ICollection<T> 有,但ICollection 没有。
  • @MicahArmantrout 您链接到通用版本。他已经说过通用版本有它。他在问为什么non-generic one 没有。
  • 可能是因为ICollection 中的Add 必须采用object,但在例如List<int>。 (您不能向List<int> 添加任何对象)但是,IList 具有Add(object),因此这个论点不太成立。原因可能是历史性的:这是它最初的制作方式,并且从未被认为值得做出如此重大的改变。
  • 答案很简单……设计师不称职。将 Add 和 Remove 放在 IList 上而不放在 ICollection 上是没有逻辑意义的,并且试图将其合理化的 cmets 是荒谬的(尽管不像 PR 粗鲁和令人反感的反智主义那么荒谬)。幸运的是,他们对泛型类有所了解,但拙劣的 ICollection 意味着您无法编写对非列表(如 HashSet 和 Dictionary)进行操作的通用代码。

标签: c# .net api-design


【解决方案1】:

在我看来,接口的命名似乎让人们感到困惑。 ICollectionICollection<T> 甚至不在同一个继承链中 - 大多数集合只是简单地实现两者。

文档说明了接口的作用,因此仅凭这一点,就不会期望Add 存在:

定义所有对象的大小、枚举器和同步方法 非泛型集合。

我怎么看?就我个人而言,我认为这要么是直接命名错误,要么是第二次(在引入通用接口时)设计师选择将 Add 放入 ICollection<T> 中,因为这一次更普遍需要它。

IList 具有Add 并继承ICollectionIList<T> 没有Add 并继承ICollection<T>,即Add

将其归结为类型层次结构设计的演变/成熟。


至于扩展方法,您可以执行以下操作:
public static void AnotherMethod<T>(this ICollection<T> collection, T item) { }

然后这样使用它:

ICollection<string> s;
s.AnotherMethod("");

【讨论】:

  • ICollection&lt;sting&gt; ...我喜欢它,也许我们可以有更多像样的音乐参考;)
【解决方案2】:

ICollection 可以是任何东西。它可能只是可枚举的东西。没有理由应该是一个Add 方法,或者实际上是一个Remove。如果您更仔细地查看界面,它几乎是只读的。您可以查看有多少元素,并且可以枚举它们。而已。以一种抽象的方式,这是完全有道理的。

当我们到达ICollection&lt;T&gt; 时,我们现在非常具体。我们确切地知道它持有什么样的对象,因此我们可以:

  • 添加&lt;T&gt;的新元素。
  • 使用IEquitable 类型的界面搜索它们。
  • 使用相同的方法删除它们。

本质上,区别在于ICollection&lt;T&gt;有点具体。

【讨论】:

  • 我有点同意你的看法,但我认为根本原因更多地与设计的演变有关。 IList 即使您不知道列表中的类型是什么,也需要添加,所有非泛型列表都有这个问题。第二次使用所有新的泛型接口,设计人员可以有机会更好地统一基础接口。要么就是这样,要么只是一个直接的命名失误。
【解决方案3】:

来自MSDN

当以多态方式代替其他集合或集合接口使用时,您不需要将集合类型添加到已知类型。例如,如果您声明一个 IEnumerable 类型的数据成员并使用它来发送 ArrayList 的实例,则无需将 ArrayList 添加到已知类型。

当您以多态方式使用集合代替非集合类型时,必须将它们添加到已知类型。例如,如果您声明一个 Object 类型的数据成员并使用它来发送 ArrayList 的实例,则将 ArrayList 添加到已知类型。

【讨论】:

    【解决方案4】:

    基于Msdn definition,是

    定义所有对象的大小、枚举器和同步方法 非泛型集合

    这意味着ICollection 表示您要读取的序列 数据。 我会说很可能支持SharePoint API 的决定是提供您从服务器读取的通用数据流

    【讨论】:

      【解决方案5】:

      一种猜测是,如果ICollection 确实有Add 方法,它会采取什么措施? Object 当然。这是在 C# 2.0 之前没有泛型数组的一个大问题。

      问题是你可以将不同的类型添加到同一个集合中

      【讨论】:

      • 这真的不是问题。你只需要在 ICollection.Add(object) 方法中进行类型检查,如果它是错误的类型就会抛出。
      • @MgSam 是对的,但仍然觉得有一个获取对象的方法是错误的,然后抛出异常。
      • MgSam:但是如果它不是泛型的,你如何定义正确的类型呢?像这样的运行时异常对我来说听起来并不有趣。话又说回来,试图猜测开发人员听起来也不好玩……
      • @AdamHouldsworth 啊,好点。我刚刚检查过 ICollection 在泛型世界之前。
      【解决方案6】:

      猜测 - ICollection 接口是扩展它的其他接口的基础接口,例如 IList 和 IDictionary。这些接口具有 add 方法的不同实现。 IList 需要一个参数,IDictionary 显然需要两个。使用泛型,派生接口方法签名并没有真正的不同,因为它们采用一个参数 - 一种类型。

      【讨论】:

      • ICollection 不扩展 ICollection!
      • 我从没说过。我说的是 System.Collections.ICollection 接口,它是在泛型之前创建的。
      【解决方案7】:

      ICollection 创建时没有通用接口。这意味着如果在ICollection 上有一个Add 方法,它必须有签名Add(object)ICollection 旨在声明跨任何类型集合的一致接口——这将强制每个集合部分地像objects 的集合一样行事。

      这已在ICollection&lt;T&gt; 中得到修复,它有一个方法Add(T)

      【讨论】:

        【解决方案8】:

        根据Albahari Brothers

        通用和非通用版本在很多方面有所不同 您可能期望的结果,尤其是在 ICollection 的情况下。

        这主要是历史原因:因为泛型来了 后来,通用接口的开发得益于 后见之明

        因此,

        ICollection&lt;T&gt;不扩展ICollection

        IList&lt;T&gt; 不扩展IList

        并且IDictionary&lt;TKey, TValue&gt; 不扩展IDictionary

        总而言之,ICollection&lt;T&gt; 已经进化到不犯ICollection 中所犯的错误。这就是为什么ICollection&lt;T&gt; 有一个Add 方法而ICollection 没有..

        【讨论】:

          猜你喜欢
          • 2011-08-31
          • 2011-11-08
          • 2010-10-14
          • 1970-01-01
          • 2019-08-09
          • 1970-01-01
          • 2011-01-22
          • 1970-01-01
          相关资源
          最近更新 更多