Propriedade Count vs método Count ()?

85

Trabalhando com uma coleção, tenho duas maneiras de obter a contagem de objetos; Count(a propriedade) e Count()(o método). Alguém sabe quais são as principais diferenças?

Posso estar errado, mas sempre uso a Countpropriedade em quaisquer instruções condicionais porque estou presumindo que o Count()método executa algum tipo de consulta na coleção, onde as já Countdevem ter sido atribuídas antes de eu 'obter'. Mas isso é um palpite - não sei se o desempenho será afetado se eu estiver errado.

EDIT: Por curiosidade, então, Count()lançará uma exceção se a coleção for nula? Porque tenho quase certeza de que a Countpropriedade simplesmente retorna 0.

d219
fonte
7
Ambos irão lançar uma exceção para coleções nulas, porque ambos estão tentando aplicar o .operador a algo que é nulo.
AaronLS

Respostas:

110

Descompilar a fonte para o Count()método de extensão revela que ele testa se o objeto é ICollection(genérico ou não) e, se for, simplesmente retorna a Countpropriedade subjacente :

Portanto, se seu código acessa em Countvez de chamar Count(), você pode ignorar a verificação de tipo - um benefício teórico de desempenho, mas duvido que seja perceptível!

// 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
fonte
10
1 por tomar a iniciativa de fazer engenharia reversa, muito útil.
Polinômio de
7
No entanto, tenha em mente que no 3.5 Count()não verifica a ICollectioninterface não genérica . Isso foi adicionado apenas no .NET 4. Ambos 3.5 e 4 verificam a ICollection<T>interface genérica .
thecoop de
2
chamar a contagem em uma sequência sem elementos lançará uma exceção. Mas Count () funcionará bem.
amesh
33

O desempenho é apenas uma razão para escolher um ou outro. Escolher .Count()significa que seu código será mais genérico. Tive ocasiões em que refatorei algum código que não produzia mais uma coleção, mas sim algo mais genérico como um IEnumerable, mas outro código quebrou como resultado porque dependia de .Counte eu tive que alterá-lo para .Count(). Se eu fizesse questão de usar em .Count()qualquer lugar, o código provavelmente seria mais reutilizável e sustentável. Normalmente, optar por utilizar interfaces mais genéricas, se puder, é sua melhor aposta. Por mais genérico, quero dizer a interface mais simples que é implementada por mais tipos e, portanto, resultando em maior compatibilidade entre o código.

Não estou dizendo que .Count()é melhor, estou apenas dizendo que há outras considerações que lidam mais com a reutilização do código que você está escrevendo.

AaronLS
fonte
2
+1 adição valiosa à discussão. Alguns códigos que estou mantendo quebraram porque a propriedade .Count não sobreviveu a uma atualização de versão do HtmlAgilityPack.
Dan Solovay
1
Isso pode ser uma faca de dois gumes. E se algum dia alguém tentar modificar o IEnumerable para ser um verdadeiro gerador. Olhando para a base de código, vejo muitos lugares onde o .Count () assume que o enumerável pode ser iterado várias vezes
bashrc
@bashrc True. Acho que se estivermos considerando a alteração do código do desenvolvedor versus a alteração do código da estrutura, é mais provável que o código do desenvolvedor mude. Se esse tipo de mudança fosse feita na estrutura, muitas coisas quebrariam. Tradicionalmente, eles introduzem novas coleções / interfaces nesses casos, para que o desenvolvedor possa migrar conforme desejado.
AaronLS
20

O .Count()método pode ser inteligente o suficiente ou saber sobre o tipo em questão e, se for, pode usar a .Countpropriedade subjacente .

Então, novamente, pode não ser.

Eu diria que é seguro presumir que, se a coleção tem uma .Countpropriedade própria, essa será sua melhor aposta quando se trata de desempenho.

Se o .Count()método não souber sobre a coleção, ele a enumerará, o que será uma operação O (n).

Lasse V. Karlsen
fonte
3
Usar a Countpropriedade poderia ser melhor, mas a Count()criação de métodos ICollection<T>.Countestá meio documentada aqui: msdn.microsoft.com/en-us/library/bb338038(v=vs.110).aspx
nawfal
Não sei como você sabe quase tudo.
snr
5

Count()método é um método de extensão que itera cada elemento de um IEnumerable<>e retorna quantos elementos existem. Se a instância de IEnumerablefor realmente um List<>, ela será otimizada para retornar a Countpropriedade em vez de iterar todos os elementos.

AntonioR
fonte
mesmo quando tenho um List <>, uso o método Count () para manter meu código mais genérico. É bom quando estou refatorando minhas classes para usar IEnumerable <> onde não há necessidade de implementação de coleção específica.
AntonioR
3

Count()existe como um método de extensão do LINQ - Counté uma propriedade em Lists, objetos de coleção .NET reais.

Como tal, Count()quase sempre será mais lento, pois enumera a coleção / objeto consultável. Em uma lista, fila, pilha, etc., use Count. Ou para uma matriz - Length.

Kieren Johnstone
fonte
3

Versão resumida: se você tem a opção de escolher entre uma Countpropriedade e um Count()método, escolha sempre a propriedade.

A diferença está principalmente em torno da eficiência da operação. Todas as coleções BCL que expõem uma Countpropriedade o fazem de maneira O (1). No Count()entanto, o método pode custar, e frequentemente custará O (N). Existem algumas verificações para tentar chegar a O (1) para algumas implementações, mas isso não é garantido de forma alguma.

JaredPar
fonte
Acho que esta resposta é mais razoável para usar a propriedade de contagem
AT
3

Se houver uma propriedade Countou Length, você deve sempre preferir isso ao Count()método, que geralmente itera a coleção inteira para contar o número de elementos dentro dela. As exceções seriam quando o Count()método fosse contra uma fonte LINQ to SQL ou LINQ to Entities, por exemplo, caso em que ele executaria uma consulta de contagem na fonte de dados. Mesmo assim, se houver uma Countpropriedade, você preferiria que ela, já que provavelmente teria menos trabalho a fazer.

Dave C
fonte
3

O Count()método é o método LINQ que funciona em qualquer IEnumerable<>. Você esperaria que o Count()método iterasse em toda a coleção para encontrar a contagem, mas acredito que o código LINQ realmente tem algumas otimizações para detectar se uma propriedade Count existe e, se houver, use-a.

Portanto, os dois devem fazer coisas quase idênticas. A propriedade Count é provavelmente um pouco melhor, pois não precisa haver uma verificação de tipo lá.

Dylan Smith
fonte