【问题标题】:Does an ICollection<T> have an order?ICollection<T> 有订单吗?
【发布时间】:2012-02-03 17:37:32
【问题描述】:

按照a public APIs should never return a list 的规则,我正在盲目转换所有返回列表的代码,改为返回ICollection&lt;T&gt;

public IList<T> CommaSeparate(String value) {...}

变成

public ICollection<T> CommaSeparate(String value) {...}

虽然ICollectionCount,但无法通过该索引获取项目。

虽然ICollection 公开了一个枚举器(允许foreach),但我认为不能保证枚举的顺序从列表的“顶部”开始,而不是“底部”。

我可以通过避免使用ICollection 来缓解这种情况,而是使用Collection

public Collection<T> Commaseparate(String value) {...}

这允许使用Items[index] 语法。

不幸的是,我的内部实现构造了一个数组;我可以转换为返回IListICollection,但不能作为Collection

有没有办法按顺序访问集合中的项目

这引出了一个更广泛的问题:ICollection 甚至 订单吗?


从概念上讲,想象我想解析一个命令行字符串。保持项目的顺序至关重要。

从概念上讲,我需要一个指示“有序”字符串元组集的合同。在API合约的情况下,为了表明顺序,以下哪项是正确的:

IEnumerable<String> Grob(string s)

ICollection<String> Grob(string s)

IList<String> Grob(string s)

Collection<String> Grob(string s)

List<String> Grob(string s)

【问题讨论】:

  • 顺便说一句,我认为您误读了作为重构基础引用的原始文章。它说不要传递List&lt;T&gt;(类)的实例,而不是IList&lt;T&gt;(接口)。如果接口需要索引访问,那么传递IList&lt;T&gt; 是完全合法的恕我直言。
  • LINQ OrderBy 返回的 IOrderedEnumerable 怎么样?

标签: c# collections icollection


【解决方案1】:

ICollection&lt;T&gt; 接口没有指定任何关于订单的内容。对象将按照返回的对象指定的顺序排列。例如,如果您返回 SortedDictionaryValues 集合,则对象将按照字典的比较器定义的顺序排列。

如果您需要该方法通过协定返回一个其协定需要特定顺序的类型,那么您应该在方法的签名中通过返回更具体的类型来表达这一点。

无论返回对象的运行时类型如何,考虑静态引用为IList&lt;T&gt;ICollection&lt;T&gt; 时的行为:当您调用GetEnumerator() 时(可能在foreach 循环中隐含),您将调用相同的方法并获得相同的对象,无论引用的静态类型如何。因此,无论CommaSeparate() 方法的返回类型如何,它的行为方式都相同。

补充一点:

正如其他人指出的那样,FXCop 规则警告不要使用List&lt;T&gt;,而不是IList&lt;T&gt;;您链接到的问题是询问为什么 FXCop 不建议使用 IList&lt;T&gt; 代替 List&lt;T&gt;,这是另一回事。如果我想象你正在解析一个顺序很重要的命令行字符串,如果我是你,我会坚持使用IList&lt;T&gt;

【讨论】:

  • 我没有实际上返回一个数组。我发生在我的实现中使用了一个数组;但这是我想隐藏的实现细节,并允许在未来进行更改。
  • @IanBoyd 明白了。无论方法返回什么类型,最后一段中关于数组的 cmets 都将适用。我将进行编辑以澄清。
  • 好极了,IList 就是这样!
【解决方案2】:

ICollection 没有保证顺序,但实际实现它的类可能(也可能没有)。

如果您想返回一个有序的集合,那么返回一个IList&lt;T&gt;,不要太沉迷于 FxCop 的一般听起来但非常笼统的建议。

【讨论】:

    【解决方案3】:

    不,ICollection 并不意味着订单。

    【讨论】:

      【解决方案4】:

      ICollection 实例具有实现它的任何类的“顺序”。也就是说,将List&lt;T&gt; 引用为ICollection 根本不会改变它的顺序。

      同样,如果您以ICollection 访问无序集合,它也不会对无序集合施加顺序。

      所以,对于你的问题:

      ICollection 甚至有订单吗?

      答案是:它完全取决于实现它的类。

      【讨论】:

        【解决方案5】:

        ICollection&lt;T&gt; 可能有一个顺序,但实际的顺序取决于实现它的类。 它没有给定索引处的项目的访问器。 IList&lt;T&gt; 专门用于提供按索引访问的接口。

        【讨论】:

        • 如果我重复 ICollection 两次,我会在同一个 orer 中两次获得项目吗?
        • 取决于实现它的类。无法保证。
        【解决方案6】:

        ICollection&lt;T&gt; 只是一个接口;它是否有序完全取决于它的底层实现(应该是不透明的)。

        如果您希望能够通过索引访问它,您希望以IList&lt;T&gt; 的形式返回内容,即IEnumerable&lt;T&gt;ICollection&lt;T&gt;。但是,应该记住,根据底层实现,获取集合中的任意项可能平均需要 O(N/2) 时间。

        我的倾向是完全避免使用“集合”接口,而是使用自定义类型根据问题域表示集合,并公开适合该类型的适当逻辑操作。 p>

        【讨论】:

          【解决方案7】:

          ICollection 只是一个接口——没有关于排序的实现或显式规范。这意味着,如果您返回以有序方式枚举的内容,那么任何消耗您的 ICollection 的东西都会以有序方式进行。

          顺序仅由底层实现对象隐含。 ICollection 中没有说明是否应该订购它。多次枚举结果将调用底层对象的枚举器,这是设置这些规则的唯一位置。一个对象不会因为继承了这个接口而改变它的枚举方式。如果接口指定它是一个有序的结果,那么你可以安全地依赖实现对象的有序结果。

          【讨论】:

          • ICollection 只是一个接口,同时也是行为规则的声明。
          • 当然可以,但是界面中没有任何内容表明应该订购或其他方式。
          【解决方案8】:

          这取决于实例的实现。碰巧是 List 的 ICollection 有顺序,碰巧是 Collection 的 ICollection 没有。

          所有 ICollections 都实现了 IEnumerable,它一次返回一个项目,无论是有序的还是其他的。

          编辑:在回复您在问题中有关命令行解析的附加示例时,我认为适当的返回类型取决于您之后对这些参数所做的事情,但 IEnumerable 可能是正确的。

          我的理由是 IList、ICollection 和它们的具体实现允许修改从 Grob 返回的列表,这可能是您不想要的。由于 .NET 没有索引序列接口,因此 IEnumerable 是防止调用者做一些奇怪的事情(例如尝试修改他们返回的参数列表)的最佳选择。

          【讨论】:

            【解决方案9】:

            如果您希望您的方法的所有当前版本和未来版本都可以轻松返回能够快速轻松地检索第 N 项的对象,请使用类型 IList&lt;T&gt; 来返回对同时实现 @ 的对象的引用987654322@ 和非通用ICollection。如果您希望某些当前或将来的版本可能无法快速轻松地返回第 N 个项目,但能够立即报告项目数,请使用类型 ICollection&lt;T&gt; 来返回实现 ICollection&lt;T&gt; 的引用以及非通用ICollection。如果您预计当前或将来的版本即使知道有多少项目也可能会遇到问题,请返回IEnumerable&lt;T&gt;。排序问题无关紧要;访问第 N 个事物的能力意味着存在一个已定义的序列,但 ICollection&lt;T&gt; 对序列的表述与 IEnumerable&lt;T&gt; 一样。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2010-12-05
              • 2012-05-22
              • 2010-12-05
              • 1970-01-01
              • 2011-06-14
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多