计数属性与Count()方法?


85

使用集合,我有两种获取对象计数的方法:Count(属性)和Count()(方法)。有谁知道关键的区别是什么?

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

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


7
两者都将为null集合引发异常,因为两者都试图将.运算符应用于null值。
AaronLS 2012年

Answers:


109

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;
    }
}

10
主动为此+1反向工程,非常有帮助。
多项式

7
但是,请记住,在3​​.5Count()中不会检查非通用ICollection接口。它仅在.NET 4中添加。3.5和4都检查通用ICollection<T>接口。
thecoop

2
在没有元素的序列上调用count会引发异常。但是Count()可以正常工作。
amesh 2013年

33

性能只是选择其中一项的原因之一。选择.Count()意味着您的代码将更加通用。在某些情况下,我重构了一些不再产生集合的代码,而是重构了诸如IEnumerable之类的更通用的代码,但由于依赖于该代码.Count而不得不将其他代码更改为,结果导致其他代码崩溃了.Count()。如果我提出要.Count()在任何地方都使用它,那么该代码将可能更具可重用性和可维护性。通常最好选择使用更通用的接口,如果可以的话,这是最好的选择。泛型是指由更多类型实现的更简单的接口,从而使您在代码之间具有更大的兼容性。

我并不是说.Count()更好,而是要考虑其他一些因素,这些因素更多地涉及正在编写的代码的可重用性。


2
+1宝贵的讨论内容。我正在维护的一些代码刚刚中断,因为属性.Count不能在HtmlAgilityPack的版本升级中幸免。
丹·索洛维

1
那可能是双刃剑。如果某天有人试图将IEnumerable修改为真正的生成器,该怎么办?看一下代码库,我发现很多地方.Count()假定可枚举可以迭代多次
bashrc

@bashrc是的。我认为,如果我们考虑开发人员代码更改与框架代码更改,则开发人员代码更可能会更改。如果在框架中进行了这种更改,那么它将破坏很多事情。传统上,在这种情况下,它们会引入新的集合/接口,以便开发人员可以根据需要进行迁移。
AaronLS '17

20

.Count()方法可能足够聪明,或者知道所涉及的类型,如果可以,则可以使用基础.Count属性。

再说一次,可能不会。

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

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


3
使用该Count属性可能会更好,但是Count()使用ICollection<T>.Count此方法的方法在此处有所记录:msdn.microsoft.com/en-us/library/bb338038
v=vs.110).aspx

我不知道你怎么都知道。
snr

5

Count()method是一个扩展方法,它迭代an的每个元素IEnumerable<>并返回其中有多少个元素。如果实例IEnumerable实际上是List<>,则已对其进行优化以返回该Count属性,而不是迭代所有元素。


即使当我有一个List <>时,我也使用Count()方法使我的代码更通用。当我将类重构为使用IEnumerable <>时,这是很好的,而无需特定的集合实现。
AntonioR 2011年

3

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

这样,Count()由于将枚举collection / queryable对象,因此几乎总是比较慢。在列表,队列,堆栈等上,使用Count。或对于数组- Length


3

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

区别主要在于操作效率。所有公开Count属性的BCL集合都以O(1)方式这样做。Count()但是,该方法可能并且经常会花费O(N)。有一些检查尝试将其实现为O(1),但绝对不能保证。


我认为使用计数属性更合理
AT

3

如果存在CountLength属性,则应始终优先于Count()方法,该方法通常会迭代整个集合以计算其中的元素数量。例如,当该Count()方法针对LINQ to SQL或LINQ to Entities源时,将是例外,在这种情况下,它将对数据源执行计数查询。即使这样,如果有一个Count属性,您还是希望使用它,因为它可能要做的工作较少。


3

Count()方法是适用于任何方法的LINQ方法IEnumerable<>。您会期望Count()方法可以遍历整个集合以找到计数,但是我相信LINQ代码实际上在其中进行了一些优化,以检测Count属性是否存在以及是否使用它。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.