¿Cuenta propiedad vs método Count ()?

85

Trabajando con una colección, tengo dos formas de obtener el recuento de objetos; Count(la propiedad) y Count()(el método). ¿Alguien sabe cuáles son las diferencias clave?

Puede que esté equivocado, pero siempre uso la Countpropiedad en las declaraciones condicionales porque supongo que el Count()método realiza algún tipo de consulta contra la colección, donde ya Countdebe haber sido asignado antes de que yo 'obtenga'. Pero eso es una suposición, no sé si el rendimiento se verá afectado si me equivoco.

EDITAR: Entonces, por curiosidad, ¿ Count()lanzará una excepción si la colección es nula? Porque estoy bastante seguro de que la Countpropiedad simplemente devuelve 0.

d219
fuente
7
Ambos lanzarán una excepción para las colecciones nulas, porque ambos están intentando aplicar el .operador a algo que es nulo.
AaronLS

Respuestas:

109

La descompilación de la fuente para el Count()método de extensión revela que prueba si el objeto es un ICollection(genérico o no) y, si es así, simplemente devuelve el subyacenteCount propiedad :

Por lo tanto, si su código accede en Countlugar de llamar Count(), puede omitir la verificación de tipos, un beneficio de rendimiento teórico, ¡pero dudo que sea notable!

// 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;
    }
}
Ian Nelson
fuente
10
+1 por tomar la iniciativa de aplicar ingeniería inversa a esto, muy útil.
Polinomio
7
Sin embargo, tenga en cuenta que en 3.5 Count()no se comprueba la ICollectioninterfaz no genérica . Esto solo se agregó en .NET 4. Tanto 3.5 como 4 verifican la ICollection<T>interfaz genérica .
thecoop
2
llamar a count en una secuencia sin elementos lanzará una excepción. Pero Count () funcionará bien.
amesh
33

El rendimiento es solo una de las razones para elegir uno u otro. Elegir .Count()significa que su código será más genérico. He tenido ocasiones en las que refactoricé un código que ya no producía una colección, sino algo más genérico como un IEnumerable, pero otro código se rompió como resultado porque dependía .County tuve que cambiarlo a .Count(). Si me propuse usar.Count() todas partes, el código probablemente sería más reutilizable y fácil de mantener. Por lo general, optar por utilizar las interfaces más genéricas si puede salirse con la suya es su mejor opción. Por más genérico, me refiero a la interfaz más simple que se implementa con más tipos y, por lo tanto, le proporciona una mayor compatibilidad entre el código.

No digo que .Count()sea ​​mejor, solo digo que hay otras consideraciones que se ocupan más de la reutilización del código que está escribiendo.

AaronLS
fuente
2
+1 valiosa adición a la discusión. Parte del código que mantengo acaba de romperse porque la propiedad .Count no sobrevivió a una actualización de la versión del HtmlAgilityPack.
Dan Solovay
1
Eso puede ser un arma de doble filo. ¿Qué pasa si algún día alguien intenta modificar el IEnumerable para que sea un verdadero generador? Al mirar el código base, veo muchos lugares donde .Count () asume que el enumerable se puede iterar varias veces
bashrc
@bashrc Verdadero. Creo que si estamos considerando cambiar el código del desarrollador frente al cambio del código del marco, es más probable que el código del desarrollador cambie. Si se hiciera ese tipo de cambio en el marco, se romperían muchas cosas. Tradicionalmente, introducen nuevas colecciones / interfaces en estos casos para que los desarrolladores puedan migrar como se desee.
AaronLS
20

El .Count()método puede ser lo suficientemente inteligente, o conocer el tipo en cuestión, y si es así, podría usar el.Count propiedad .

Entonces de nuevo, tal vez no.

Yo diría que es seguro asumir que si la colección tiene una .Countpropiedad en sí misma, esa será su mejor apuesta en lo que respecta al rendimiento.

Si el .Count()método no conoce la colección, la enumerará, lo que será una operación O (n).

Lasse V. Karlsen
fuente
3
El uso de la Countpropiedad podría ser mejor, pero el uso de Count()métodos ICollection<T>.Countestá documentado aquí: msdn.microsoft.com/en-us/library/bb338038(v=vs.110).aspx
nawfal
No sé cómo lo sabes casi todo.
snr
5

Count()El método es un método de extensión que itera cada elemento de un IEnumerable<>y devuelve cuántos elementos hay. Si la instancia de IEnumerablees en realidad a List<>, entonces está optimizada para devolver la Countpropiedad en lugar de iterar todos los elementos.

AntonioR
fuente
incluso cuando tengo un List <>, uso el método Count () para mantener mi código más genérico. Es bueno cuando estoy refactorizando mis clases para usar IEnumerable <> donde no hay necesidad de una implementación de colección específica.
AntonioR
3

Count()¿Existe como un método de extensión de LINQ? Countes una propiedad en Lists, objetos de colección .NET reales.

Como tal, Count()casi siempre será más lento, ya que enumerará la colección / objeto consultable. En una lista, cola, pila, etc., utilice Count. O para una matriz - Length.

Kieren Johnstone
fuente
3

Versión corta: si puede elegir entre una Countpropiedad y un Count()método, elija siempre la propiedad.

La diferencia radica principalmente en la eficiencia de la operación. Todas las colecciones de BCL que exponen una Countpropiedad lo hacen de forma O (1). Sin Count()embargo, el método puede costar, y con frecuencia lo hará, O (N). Hay algunas comprobaciones para intentar llevarlo a O (1) para algunas implementaciones, pero de ninguna manera está garantizado.

JaredPar
fuente
Creo que esta respuesta es más razonable para usar la propiedad de conteo
AT
3

Si hay una propiedad Counto Length, siempre debe preferir eso al Count()método, que generalmente itera toda la colección para contar el número de elementos dentro. Las excepciones serían cuando el Count()método está en contra de una fuente LINQ to SQL o LINQ to Entities, por ejemplo, en cuyo caso realizaría una consulta de recuento contra la fuente de datos. Incluso entonces, si hay una Countpropiedad, querrá preferirla, ya que probablemente tenga menos trabajo que hacer.

Dave C
fuente
3

El Count()método es el método LINQ que funciona en cualquier IEnumerable<>. Esperarías elCount() método itere sobre toda la colección para encontrar el recuento, pero creo que el código LINQ en realidad tiene algunas optimizaciones para detectar si existe una propiedad de recuento y, de ser así, úsela.

Entonces ambos deberían hacer cosas casi idénticas. La propiedad Count probablemente sea un poco mejor, ya que no es necesario que haya una verificación de tipo allí.

Dylan Smith
fuente