Count属性与Count()方法有什么区别?

108

在处理集合时,我知道有两种方式可以获取对象的数量:Count(属性)和Count()(方法)。有没有人知道它们之间的关键区别?

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

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


9
对于空集合,两者都会抛出异常,因为它们都试图对为空的东西应用 . 运算符。 - AaronLS
10个回答

141

反编译 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;
    }
}

15
感谢您采取主动反向工程,这非常有帮助。+1 - Polynomial
7
请注意,在3.5版本中,Count()方法不会检查非泛型的ICollection接口,这个功能只在.NET 4中添加。无论是3.5还是4,都会检查泛型的ICollection<T>接口。 - thecoop
4
对一个没有元素的序列调用Count属性将引发异常,但Count()方法可以正常工作。 - amesh

43

性能只是选择其中一种方法的原因,而不是唯一的原因。 选择 .Count() 意味着您的代码将更加通用。 我曾经遇到过这样的情况,我重构了一些代码,并非产生集合,而是像 IEnumerable 这样更通用的东西,但由于依赖于 .Count 的其他代码导致代码出现故障,因此我不得不将其更改为 .Count()。如果我在所有地方使用 .Count(),则代码可能会更具可重用性和可维护性。通常,如果可以做到这一点,最好选择使用更通用的接口。 通过更通用,我指的是实现更多类型的简单接口,从而在代码之间获得更大的兼容性。

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


3
对讨论有很有价值的补充。我正在维护的一些代码因为HtmlAgilityPack的版本升级而导致.Count属性无法使用。 - Dan Solovay
2
这可能是一把双刃剑。如果有一天有人尝试将IEnumerable修改为真正的生成器,会怎样呢?看着代码库,我发现很多地方都假定可枚举对象可以被多次迭代,而.Count()方法就是其中之一。 - bashrc
@bashrc 确实。如果我们考虑开发者的代码更改与框架代码更改,那么开发者代码更有可能发生变化。如果在框架中进行了这种类型的更改,它将破坏很多东西。传统上,在这些情况下引入新的集合/接口,以便开发者可以根据需要进行迁移。 - AaronLS

24
.Count()方法可能很聪明,或者知道查询的类型,如果是这样的话,它可能会使用底层的.Count属性。
然而,它也可能不会。
我认为可以安全地假设,如果集合本身具有.Count属性,那么在性能方面这将是最好的选择。
如果.Count()方法不知道集合的情况,它将枚举整个集合,这将是一个O(n)的操作。

3
可以使用 Count 属性会更好,但是使用 Count() 方法来使用 ICollection<T>.Count 在这里有一定的文档说明:https://msdn.microsoft.com/zh-cn/library/bb338038(v=vs.110).aspx - nawfal
1
我不知道你怎么几乎什么都知道。 - Soner from The Ottoman Empire

6
简要版:如果你在一个属性和一个方法之间可以选择,首选属性。这两者的区别主要在于操作的效率。所有公开 Count 属性的 BCL 集合都是以 O(1) 的方式实现的。而 Count() 方法常常需要 O(N) 的成本。尽管某些实现尝试进行一些检查以使其变为 O(1),但这并不保证。
详细版:如果你需要在 .NET Framework 中计算集合中元素的数量,你可能会遇到两个方法:Count 属性和 Count() 方法。这两个方法的区别在于它们执行该操作的效率。Count 属性提供了实时返回元素数量的能力,并且以 O(1) 的时间复杂度运行,这意味着无论集合中有多少元素,计算时间始终相同。另一方面,Count() 方法通常需要 O(N) 的时间来计算元素数量,其中 N 是集合中的元素数。事实上,在大多数情况下,Count() 方法都比 Count 属性慢得多。当然,在某些特殊情况下,Count() 方法可能会更快。例如,对于字符串类型的集合,Count() 方法可以在常量时间内计算元素数量。但总体来说,如果你需要计算集合中的元素数量,请使用 Count 属性,因为它具有更高的效率。

我认为使用计数属性更合理。 - A.T.

5
Count() 方法是适用于任何 IEnumerable<> 的 LINQ 方法。 你可能会认为 Count() 方法会遍历整个集合来查找计数,但我相信 LINQ 代码实际上有一些优化措施来检测是否存在 Count 属性,如果存在,则使用它。
因此,它们两个应该做几乎相同的事情。Count 属性可能稍微好一些,因为其中不需要进行类型检查。

5

Count()方法是一个扩展方法,它遍历IEnumerable<>的每个元素并返回元素数量。如果IEnumerable实例实际上是一个List<>,那么它会优化返回Count属性而不是遍历所有元素。


即使我有一个List<>,我也使用Count()方法使我的代码更通用。当我重构我的类以使用IEnumerable<>时,这是很好的选择,因为没有特定的集合实现需求。 - AntonioR

4

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

因此,由于它将枚举集合/可查询对象,所以 Count()几乎总是更慢。 在列表、队列、栈等中使用 Count 。 或对于数组-使用 Length


3
如果一个集合有CountLength属性,你应该总是优先使用它们而不是Count()方法,因为后者通常需要迭代整个集合来计算元素数量。例外情况是当Count()方法针对LINQ to SQL或LINQ to Entities源时,它会执行一次针对数据源的计数查询。即使如此,如果存在Count属性,你仍然应该优先使用它,因为它可能需要更少的工作量。

0

Count() 方法对于 ICollection<T> 进行了优化,这将导致调用 Count 属性。在这种情况下,性能上可能没有显著的差异。

除了 ICollection<T> 之外,还有其他类型具有比 Count() 扩展方法更高效的替代方法。此代码分析性能规则适用于以下类型。

CA1829:使用 Length/Count 属性而不是 Enumerable.Count 方法。

System.Array
System.Collections.Immutable.ImmutableArray<T>
System.Collections.ICollection
System.Collections.Generic.ICollection<T>
System.Collections.Generic.IReadOnlyCollection<T>

所以,如果可用,我们应该使用CountLength属性,否则回退到Count()扩展方法。

0

.Count 是集合的一个属性,用于获取集合中的元素。与 .Count() 不同,后者是 LINQ 的扩展方法,用于计算元素的数量。

通常情况下,.Count.Count() 更快,因为它不需要创建和枚举 LINQ 查询的开销。

除非需要 .Count() 方法提供的额外功能(例如指定过滤谓词的能力),否则最好使用 .Count 属性。

int count = numbers.Count(n => n.Id == 100);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接