Count proprietà vs metodo Count ()?


85

Lavorando con una raccolta ho due modi per ottenere il conteggio degli oggetti; Count(la proprietà) e Count()(il metodo). Qualcuno sa quali sono le differenze principali?

Potrei sbagliarmi, ma utilizzo sempre la Countproprietà in qualsiasi istruzione condizionale perché presumo che il Count()metodo esegua una sorta di query sulla raccolta, dove as Countdeve essere già stato assegnato prima di me "get". Ma è un'ipotesi: non so se le prestazioni saranno influenzate se sbaglio.

EDIT: Per curiosità, quindi, verrà Count()generata un'eccezione se la raccolta è nulla? Perché sono abbastanza sicuro che la Countproprietà restituisca semplicemente 0.


7
Entrambi genereranno un'eccezione per le raccolte null, perché entrambi stanno cercando di applicare l' .operatore a qualcosa che è null.
AaronLS

Risposte:


110

La decompilazione del sorgente per il Count()metodo di estensione rivela che verifica se l'oggetto è un ICollection(generico o meno) e in tal caso restituisce semplicemente il sottostanteCount proprietà :

Quindi, se il tuo codice accede Countinvece di chiamare Count(), puoi bypassare il controllo del tipo - un vantaggio teorico in termini di prestazioni ma dubito che sarebbe evidente!

// 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 per aver preso l'iniziativa di decodificare questo, molto utile.
Polinomio

7
Tuttavia, tieni presente che in 3.5 Count()non controlla l' ICollectioninterfaccia non generica . Questo è stato aggiunto solo in .NET 4. Sia 3.5 che 4 controllano l' ICollection<T>interfaccia generica .
thecoop

2
chiamare count su una sequenza senza elementi genererà un'eccezione. Ma Count () funzionerà bene.
amesh

33

Le prestazioni sono solo uno dei motivi per scegliere l'uno o l'altro. Scegliere .Count()significa che il tuo codice sarà più generico. Ho avuto occasioni in cui ho refactoring del codice che non produceva più una raccolta, ma qualcosa di più generico come un IEnumerable, ma altro codice si è rotto di conseguenza perché dipendeva da .Counte ho dovuto cambiarlo in .Count(). Se puntassi a usarlo .Count()ovunque, il codice sarebbe probabilmente più riutilizzabile e gestibile. Di solito scegliere di utilizzare le interfacce più generiche se riesci a farla franca è la soluzione migliore. Per più generico, intendo l'interfaccia più semplice che è implementata da più tipi, e quindi ti garantisce una maggiore compatibilità tra il codice.

Non sto dicendo che .Count()sia meglio, sto solo dicendo che ci sono altre considerazioni che riguardano maggiormente la riusabilità del codice che stai scrivendo.


2
+1 Preziosa aggiunta alla discussione. Un po 'di codice che sto mantenendo si è rotto perché la proprietà .Count non è sopravvissuta a un aggiornamento della versione di HtmlAgilityPack.
Dan Solovay

1
Potrebbe essere un'arma a doppio taglio. E se un giorno qualcuno cercasse di modificare l'IEnumerable per essere un vero generatore? Guardando la base di codice vedo molti punti in cui .Count () presume che l'enumerabile possa essere ripetuto più volte
bashrc

@bashrc True. Penso che se stiamo considerando la modifica del codice dello sviluppatore rispetto alla modifica del codice del framework, è più probabile che il codice dello sviluppatore cambierebbe. Se quel tipo di cambiamento fosse fatto nel framework, si spezzerebbe un sacco di cose. Tradizionalmente introducono nuove collezioni / interfacce in questi casi in modo che gli sviluppatori possano migrare come desiderato.
AaronLS

20

Il .Count()metodo potrebbe essere abbastanza intelligente o conoscere il tipo in questione e, in tal caso, potrebbe utilizzare la .Countproprietà sottostante .

Poi di nuovo, potrebbe non esserlo.

Direi che è lecito ritenere che se la collezione ha una .Countproprietà stessa, questa sarà la soluzione migliore quando si tratta di prestazioni.

Se il .Count()metodo non conosce la raccolta, verrà enumerata su di essa, che sarà un'operazione O (n).


3
Usando la Countproprietà potrebbe essere migliore, ma Count()il metodo facendo uso ICollection<T>.Countè un pò documentato qui: msdn.microsoft.com/en-us/library/bb338038(v=vs.110).aspx
Nawfal

Non so come fai a sapere quasi tutto.
snr

5

Count()metodo è un metodo di estensione che itera ogni elemento di un IEnumerable<>e restituisce quanti elementi ci sono. Se l'istanza di IEnumerableè effettivamente a List<>, è ottimizzata per restituire la Countproprietà invece di iterare tutti gli elementi.


anche quando ho un List <>, utilizzo il metodo Count () per mantenere il mio codice più generico. È utile quando eseguo il refactoring delle mie classi per utilizzare IEnumerable <> dove non è necessaria l'implementazione di una raccolta specifica.
AntonioR

3

Count()è presente come metodo di estensione da LINQ - Countè una proprietà su Lists, oggetti di raccolta .NET effettivi.

Come tale, Count() sarà quasi sempre più lento, poiché enumererà l'oggetto raccolta / interrogabile. In una lista, in coda, in pila ecc., Usa Count. O per un array - Length.


3

Versione breve: se puoi scegliere tra una Countproprietà e un fileCount() metodo, scegli sempre la proprietà.

La differenza è principalmente intorno all'efficienza dell'operazione. Tutte le raccolte BCL che espongono una Countproprietà lo fanno in modo O (1). Il Count()metodo però può, e spesso costerà O (N). Ci sono alcuni controlli per provare a portarlo a O (1) per alcune implementazioni ma non è affatto garantito.


Penso che questa risposta sia più ragionevole per utilizzare la proprietà count
AT

3

Se è presente una proprietà Countor Length, dovresti sempre preferirla al Count()metodo, che generalmente itera l'intera raccolta per contare il numero di elementi all'interno. Le eccezioni si verificano quando il Count()metodo è su un'origine LINQ to SQL o LINQ to Entities, nel qual caso esegue una query di conteggio sull'origine dati. Anche allora, se c'è una Countproprietà, preferiresti quella, poiché probabilmente ha meno lavoro da fare.


3

Il Count()metodo è il metodo LINQ che funziona su qualsiasi IEnumerable<>. Ci si aspetterebbe che il Count()metodo iterasse sull'intera raccolta per trovare il conteggio, ma credo che il codice LINQ abbia effettivamente alcune ottimizzazioni per rilevare se esiste una proprietà Count e, in tal caso, utilizzarla.

Quindi entrambi dovrebbero fare cose quasi identiche. La proprietà Count è probabilmente leggermente migliore poiché non è necessario che vi sia un controllo del tipo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.