Count-Eigenschaft vs Count () -Methode?

84

Wenn ich mit einer Sammlung arbeite, habe ich zwei Möglichkeiten, die Anzahl der Objekte zu ermitteln. Count (die Eigenschaft) und Count () die Methode. Weiß jemand, was die Hauptunterschiede sind? Ich könnte mich irren, aber ich verwende die Count-Eigenschaft immer in allen bedingten Anweisungen, da ich davon ausgehe, dass die Count () -Methode eine Art Abfrage für die Auflistung ausführt, bei der Count bereits zugewiesen worden sein muss, bevor ich sie abrufe. Aber das ist eine Vermutung - ich weiß nicht, ob die Leistung beeinträchtigt wird, wenn ich falsch liege.

EDIT: Wird Count () dann aus Neugier eine Ausnahme auslösen, wenn die Sammlung null ist? Weil ich mir ziemlich sicher bin, dass die Count-Eigenschaft einfach 0 zurückgibt.


quelle
7
Beide lösen eine Ausnahme für Nullsammlungen aus, da beide versuchen, den .Operator auf etwas anzuwenden, das null ist.
AaronLS

Antworten:

107

Das Dekompilieren der Quelle für die Count()Erweiterungsmethode zeigt, dass getestet wird, ob das Objekt ein ICollection(generisches oder anderes) Objekt ist, und wenn ja, einfach die zugrunde liegende CountEigenschaft zurückgegeben wird:

Wenn Ihr Code also zugreift, Countanstatt aufzurufen Count(), können Sie die Typprüfung umgehen - ein theoretischer Leistungsvorteil, aber ich bezweifle, dass dies spürbar wäre!

// 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
quelle
10
+1 für das Ergreifen der Initiative zum Reverse Engineering, sehr hilfreich.
Polynom
7
Beachten Sie jedoch, dass in 3.5 Count()nicht nach der nicht generischen ICollectionSchnittstelle gesucht wird. Dies wurde nur in .NET 4 hinzugefügt. Sowohl 3.5 als auch 4 prüfen die generische ICollection<T>Schnittstelle.
Thecoop
2
Wenn Sie count für eine Sequenz ohne Elemente aufrufen, wird eine Ausnahme ausgelöst. Aber Count () wird gut funktionieren.
Amesh
33

Leistung ist nur ein Grund, sich für den einen oder anderen zu entscheiden. Wenn Sie .Count () auswählen, wird Ihr Code allgemeiner. Ich hatte Gelegenheiten, in denen ich Code überarbeitet habe, der keine Sammlung mehr produzierte, sondern etwas allgemeineres wie eine IEnumerable, aber anderer Code ist infolgedessen kaputt gegangen, weil er davon abhing .Countund ich ihn ändern musste .Count(). Wenn ich darauf hinweisen würde, .Count()überall zu verwenden , wäre der Code wahrscheinlich wiederverwendbarer und wartbarer. Normalerweise ist es die beste Wahl, die allgemeineren Schnittstellen zu verwenden, wenn Sie damit durchkommen können. Mit allgemeiner meine ich die einfachere Schnittstelle, die von mehr Typen implementiert wird und somit eine größere Kompatibilität zwischen Code ermöglicht.

Ich sage nicht, dass .Count()es besser ist, ich sage nur, dass es andere Überlegungen gibt, die sich mehr mit der Wiederverwendbarkeit des Codes befassen, den Sie schreiben.

AaronLS
quelle
2
+1 Wertvolle Ergänzung zur Diskussion. Ein Code, den ich pflege, ist nur kaputt gegangen, weil die Eigenschaft .Count ein Versions-Upgrade des HtmlAgilityPack nicht überlebt hat.
Dan Solovay
Das kann ein zweischneidiges Schwert sein. Was ist, wenn eines Tages jemand versucht, die IEnumerable so zu ändern, dass sie ein echter Generator ist? Wenn ich mir die Codebasis ansehe, sehe ich viele Stellen, an denen .Count () davon ausgeht, dass die
Aufzählung
@bashrc True. Ich denke, wenn wir überlegen, den Code des Entwicklers im Vergleich zum Framework-Code zu ändern, ist es wahrscheinlicher, dass sich der Entwicklercode ändert. Wenn diese Art von Änderung im Rahmen vorgenommen würde, würde dies eine Menge Dinge zerstören. Traditionell führen sie in diesen Fällen neue Sammlungen / Schnittstellen ein, damit Entwickler nach Bedarf migrieren können.
AaronLS
20

Die .Count()Methode ist möglicherweise intelligent genug oder kennt den betreffenden Typ. In diesem Fall wird möglicherweise die zugrunde liegende .CountEigenschaft verwendet.

Andererseits könnte es nicht.

Ich würde sagen, es ist sicher anzunehmen, dass wenn die Sammlung selbst eine .CountEigenschaft hat, dies die beste Wahl ist, wenn es um die Leistung geht.

Wenn die .Count()Methode nichts über die Auflistung weiß, zählt sie darüber auf, was eine O (n) -Operation ist.

Lasse V. Karlsen
quelle
2
Die Verwendung der CountEigenschaft könnte besser sein, aber die Count()Methodenerstellung ICollection<T>.Countwird hier irgendwie dokumentiert: msdn.microsoft.com/en-us/library/bb338038(v=vs.110).aspx
nawfal
Ich weiß nicht, woher du fast alles weißt.
snr
5

Die Count () -Methode ist eine Erweiterungsmethode, die jedes Element einer IEnumerable <> iteriert und zurückgibt, wie viele Elemente vorhanden sind. Wenn die Instanz von IEnumerable tatsächlich eine Liste <> ist, ist sie so optimiert, dass die Count-Eigenschaft zurückgegeben wird, anstatt alle Elemente zu iterieren.

AntonioR
quelle
Selbst wenn ich eine List <> habe, verwende ich die Count () -Methode, um meinen Code allgemeiner zu halten. Es ist gut, wenn ich meine Klassen so umgestalte, dass IEnumerable <> verwendet wird, wo keine spezifische Sammlung implementiert werden muss.
AntonioR
3

Count()gibt es als Erweiterungsmethode von LINQ - Countist eine Eigenschaft für Lists, tatsächliche .NET-Auflistungsobjekte.

Als solches Count()wird es fast immer langsamer sein, da es das Sammlungs- / abfragbare Objekt auflistet. Auf einer Liste, Queue, Stapel usw., verwenden Count. Oder für ein Array - Length.

Kieren Johnstone
quelle
3

Wenn es eine Count- oder Length-Eigenschaft gibt, sollten Sie diese immer der Count () -Methode vorziehen, die im Allgemeinen die gesamte Sammlung iteriert, um die Anzahl der darin enthaltenen Elemente zu zählen. (Ausnahmen sind beispielsweise, wenn die Count () -Methode gegen eine Linq to SQL- oder Linq to Entities-Quelle gerichtet ist. In diesem Fall wird eine Count-Abfrage für die Datenquelle durchgeführt. Selbst dann, wenn eine Count-Eigenschaft vorhanden ist, würden Sie dies tun möchte das vorziehen, da es wahrscheinlich weniger Arbeit zu tun hat.)

Dave C.
quelle
3

Die Count () -Methode ist die LINQ-Methode, die auf jedem IEnumerable <> funktioniert. Sie würden erwarten, dass die Count () -Methode über die gesamte Sammlung iteriert, um die Anzahl zu ermitteln, aber ich glaube, dass der LINQ-Code tatsächlich einige Optimierungen enthält, um festzustellen, ob eine Count-Eigenschaft vorhanden ist, und wenn ja, verwenden Sie diese.

Also sollten beide fast identische Dinge tun. Die Count-Eigenschaft ist wahrscheinlich etwas besser, da dort keine Typprüfung erforderlich ist.

Dylan Smith
quelle
3

Kurzversion: Wenn Sie die Wahl zwischen einer CountEigenschaft und einer Count()Methode haben, wählen Sie immer die Eigenschaft.

Der Unterschied liegt hauptsächlich in der Effizienz des Betriebs. Alle BCL-Sammlungen, die eine CountEigenschaft verfügbar machen, tun dies auf O (1) -Methode. Die Count()Methode kann und wird jedoch häufig O (N) kosten. Es gibt einige Überprüfungen, um zu versuchen, es für einige Implementierungen auf O (1) zu bringen, aber es ist keineswegs garantiert.

JaredPar
quelle
Ich denke, diese Antwort ist vernünftiger, um count-Eigenschaft zu verwenden
AT