【问题标题】:Count property vs Count() method?Count 属性与 Count() 方法?
【发布时间】:2011-12-19 15:21:53
【问题描述】:

使用集合我有两种获取对象数量的方法; Count(属性)和Count()(方法)。有谁知道主要区别是什么?

我可能错了,但我总是在任何条件语句中使用Count 属性,因为我假设Count() 方法对集合执行某种查询,其中Count 必须已经分配在我“得到”之前。但这是一个猜测——我不知道如果我错了会不会影响性能。

编辑:那么出于好奇,如果集合为空,Count() 会抛出异常吗?因为我很确定 Count 属性只会返回 0。

【问题讨论】:

  • 两者都会为空集合抛出异常,因为两者都试图将. 运算符应用于空集合。

标签: c# linq list collections count


【解决方案1】:

Count() 方法是一种扩展方法,它迭代IEnumerable<> 的每个元素并返回有多少元素。如果IEnumerable 的实例实际上是List<>,那么它被优化为返回Count 属性而不是迭代所有元素。

【讨论】:

  • 即使我有一个 List,我也会使用 Count() 方法来使我的代码更通用。当我重构我的类以在不需要特定集合实现的情况下使用 IEnumerable 时,它很好。
【解决方案2】:

性能只是选择其中之一的原因之一。选择.Count() 意味着您的代码将更加通用。我曾经重构过一些不再生成集合的代码,而是重构了一些更通用的代码,例如 IEnumerable,但其他代码因此中断,因为它依赖于 .Count,我不得不将其更改为 .Count() .如果我强调在任何地方都使用.Count(),那么代码可能会更加可重用和可维护。通常选择使用更通用的接口,如果你能逃脱它是你最好的选择。更通用是指由更多类型实现的更简单的接口,从而为您提供更好的代码兼容性。

我并不是说.Count() 更好,我只是说还有其他考虑因素可以更多地处理您正在编写的代码的可重用性。

【讨论】:

  • +1 对讨论的有价值的补充。我维护的一些代码刚刚损坏,因为属性 .Count 在 HtmlAgilityPack 的版本升级中无法幸免。
  • 这可能是一把双刃剑。如果有一天有人试图将 IEnumerable 修改为真正的生成器怎么办。查看代码库,我看到很多地方 .Count() 假定可枚举可以迭代多次
  • @bashrc 是的。我认为,如果我们正在考虑开发人员的代码更改与框架代码的更改,那么开发人员代码更有可能发生更改。如果在框架中进行这种更改,它会破坏很多东西。传统上,他们在这些情况下引入新的集合/接口,以便开发人员可以根据需要进行迁移。
【解决方案3】:

Count() 方法是适用于任何IEnumerable<> 的 LINQ 方法。您可能希望 Count() 方法遍历整个集合以找到计数,但我相信 LINQ 代码实际上有一些优化来检测是否存在 Count 属性,如果存在则使用它。

所以他们都应该做几乎相同的事情。 Count 属性可能会稍微好一些,因为那里不需要进行类型检查。

【讨论】:

    【解决方案4】:

    如果有 CountLength 属性,您应该始终更喜欢 Count() 方法,后者通常会迭代整个集合以计算其中的元素数量。例如,Count() 方法针对 LINQ to SQL 或 LINQ to Entities 源时例外,在这种情况下,它将针对数据源执行计数查询。即便如此,如果有 Count 属性,您会更喜欢它,因为它可能需要做的工作更少。

    【讨论】:

      【解决方案5】:

      .Count() 方法可能足够聪明,或者知道有问题的类型,如果是这样,它可能使用底层的 .Count 属性。

      再一次,它可能不会。

      我想说的是,如果集合本身具有 .Count 属性,那么就性能而言,这将是您最好的选择。

      如果.Count() 方法不知道该集合,它将对其进行枚举,这将是一个 O(n) 操作。

      【讨论】:

      【解决方案6】:

      Count() 扩展方法的源代码进行反编译表明它会测试对象是否为ICollection(通用或其他),如果是则简单地返回底层Count 属性:

      因此,如果您的代码访问 Count 而不是调用 Count(),则可以绕过类型检查 - 理论上的性能优势,但我怀疑它会是一个明显的优势!

      // System.Linq.Enumerable
      public static int Count<TSource>(this IEnumerable<TSource> source)
      {
          checked
          {
              if (source == null)
              {
                  throw Error.ArgumentNull("source");
              }
              ICollection<TSource> collection = source as ICollection<TSource>;
              if (collection != null)
              {
                  return collection.Count;
              }
              ICollection collection2 = source as ICollection;
              if (collection2 != null)
              {
                  return collection2.Count;
              }
              int num = 0;
              using (IEnumerator<TSource> enumerator = source.GetEnumerator())
              {
                  while (enumerator.MoveNext())
                  {
                      num++;
                  }
              }
              return num;
          }
      }
      

      【讨论】:

      • +1 表示主动对此进行逆向工程,非常有帮助。
      • 但是,请记住,在 3.5 中,Count() 不会检查非通用 ICollection 接口。这仅在 .NET 4 中添加。3.5 和 4 都检查通用 ICollection&lt;T&gt; 接口。
      • 在没有元素的序列上调用 count 将引发异常。但是 Count() 可以正常工作。
      【解决方案7】:

      短版:如果您可以在Count 属性和Count() 方法之间进行选择,请始终选择该属性。

      区别主要在于操作的效率。所有暴露 Count 属性的 BCL 集合都以 O(1) 方式进行。 Count() 方法虽然可以而且经常会花费 O(N)。对于某些实现,有一些检查可以尝试使其达到 O(1),但这绝不是保证。

      【讨论】:

      • 我认为这个答案使用count属性更合理
      【解决方案8】:

      Count() 是 LINQ 的扩展方法 - CountLists 上的一个属性,是实际的 .NET 集合对象。

      因此,Count() 几乎总是会变慢,因为它会枚举集合/可查询对象。在列表、队列、堆栈等上,使用Count。或者对于一个数组 - Length

      【讨论】:

        猜你喜欢
        • 2016-01-12
        • 1970-01-01
        • 2014-02-10
        • 1970-01-01
        • 1970-01-01
        • 2010-09-23
        • 2016-12-23
        • 1970-01-01
        相关资源
        最近更新 更多