private IEnumerable<string> Tables
{
get
{
yield return "Foo";
yield return "Bar";
}
}
Nehmen wir an, ich möchte diese iterieren und so etwas wie die Verarbeitung von #n von #m schreiben.
Gibt es eine Möglichkeit, den Wert von m herauszufinden, ohne vor meiner Hauptiteration zu iterieren?
Ich hoffe ich habe mich klar gemacht.
c#
.net
ienumerable
Sebagomez
quelle
quelle
Die
System.Linq.Enumerable.Count
Erweiterungsmethode onIEnumerable<T>
hat die folgende Implementierung:Also versucht es zu werfen
ICollection<T>
, was eineCount
Eigenschaft hat, und verwendet diese, wenn möglich. Andernfalls iteriert es.Daher ist es am besten, die
Count()
Erweiterungsmethode für IhrIEnumerable<T>
Objekt zu verwenden, da Sie auf diese Weise die bestmögliche Leistung erzielen.quelle
ICollection<T>
.T
aufIEnumerator<T> enumerator = source.GetEnumerator()
, einfach, dies zu tun:IEnumerator enumerator = source.GetEnumerator()
und sollte funktionieren!IEnumerable<T>
erbtIDisposable
, wodurch dieusing
Anweisung sie automatisch entsorgen kann.IEnumerable
nicht. Also, wenn Sie so oder so anrufenGetEnumerator
, sollten Sie mitvar d = e as IDisposable; if (d != null) d.Dispose();
Fügen Sie einfach einige zusätzliche Informationen hinzu:
Die
Count()
Erweiterung iteriert nicht immer. Betrachten Sie Linq to Sql, wo die Anzahl in die Datenbank geht. Anstatt jedoch alle Zeilen zurückzubringen, wird derCount()
Befehl Sql ausgegeben und stattdessen das Ergebnis zurückgegeben.Darüber hinaus ist der Compiler (oder die Laufzeit) so intelligent, dass er die Objektmethode
Count()
aufruft, falls vorhanden. Es ist also nicht so, wie andere Antwortende sagen, völlig ignorant zu sein und immer zu iterieren, um Elemente zu zählen.In vielen Fällen, in denen der Programmierer nur
if( enumerable.Count != 0 )
mit derAny()
Erweiterungsmethode prüft ,if( enumerable.Any() )
ist dies bei der verzögerten Auswertung von linq weitaus effizienter, da er kurzschließen kann, sobald er feststellt, dass Elemente vorhanden sind. Es ist auch besser lesbarquelle
.Count
Eigenschaft, da sie immer weiß, wie groß sie ist. Wenn bei der Abfragecollection.Count
keine zusätzliche Berechnung erfolgt, wird einfach die bereits bekannte Anzahl zurückgegeben. Das Gleiche gilt fürArray.length
soweit ich weiß. Allerdings.Any()
bekommt den enumerator der Quelleusing (IEnumerator<TSource> enumerator = source.GetEnumerator())
und liefert true , wenn es tun kannenumerator.MoveNext()
. Für Sammlungen :if(collection.Count > 0)
, Arrays:if(array.length > 0)
und für Aufzählungenif(collection.Any())
.IQueryably<T>
inIEnumerable<T>
a umwandeln, wird keine SQL-Anzahl ausgegeben. Als ich das schrieb, war Linq to Sql neu; Ich glaube, ich habe nur daraufAny()
gedrängt, es zu verwenden, weil es für Aufzählungen, Sammlungen und SQL (im Allgemeinen) viel effizienter und lesbarer war. Vielen Dank für die Verbesserung der Antwort.Ein Freund von mir hat eine Reihe von Blog-Posts, die veranschaulichen, warum Sie dies nicht tun können. Er erstellt eine Funktion, die eine IEnumerable zurückgibt, wobei jede Iteration die nächste Primzahl bis zu zurückgibt
ulong.MaxValue
und das nächste Element erst berechnet wird, wenn Sie danach fragen. Schnelle Pop-Frage: Wie viele Artikel werden zurückgegeben?Hier sind die Beiträge, aber sie sind ziemlich lang:
quelle
EnumerableFeatures
Objekt zurückgibt ) nicht erfordert, dass Enumeratoren etwas Schwieriges tun, sondern in der Lage sind, solche Fragen zu stellen (zusammen mit einigen anderen wie "Können Sie es versprechen?" Geben Sie immer die gleiche Reihenfolge von Elementen zurück. "," Können Sie sicher Code ausgesetzt sein, der Ihre zugrunde liegende Sammlung nicht ändern sollte? "usw.) wäre sehr nützlich.set yield options
Erklärung oder ähnliches erhalten, um diese zu unterstützen. Wenn es richtig entworfen ist,IEnhancedEnumerator
könnte es Dinge wie LINQ vielToArray
ToList
Enumerable.Concat
verwendet werden, um eine große Sammlung, die viel über sich selbst weiß, mit einer kleinen Sammlung zu kombinieren, die dies nicht tut.IEnumerable kann nicht ohne Iteration zählen.
Unter "normalen" Umständen können Klassen, die IEnumerable oder IEnumerable <T> implementieren, wie z. B. List <T>, die Count-Methode implementieren, indem sie die List <T> .Count-Eigenschaft zurückgeben. Die Count-Methode ist jedoch keine Methode, die auf der IEnumerable <T> - oder IEnumerable-Schnittstelle definiert ist. (Der einzige, der tatsächlich ist, ist GetEnumerator.) Dies bedeutet, dass keine klassenspezifische Implementierung dafür bereitgestellt werden kann.
Count it ist vielmehr eine Erweiterungsmethode, die in der statischen Klasse Enumerable definiert ist. Dies bedeutet, dass es für jede Instanz einer von IEnumerable <T> abgeleiteten Klasse aufgerufen werden kann, unabhängig von der Implementierung dieser Klasse. Es bedeutet aber auch, dass es an einem einzigen Ort außerhalb einer dieser Klassen implementiert wird. Was natürlich bedeutet, dass es auf eine Weise implementiert werden muss, die völlig unabhängig von den Interna dieser Klasse ist. Die einzige Möglichkeit zum Zählen ist die Iteration.
quelle
Alternativ können Sie Folgendes tun:
quelle
Nein, im Allgemeinen nicht. Ein Punkt bei der Verwendung von Aufzählungszeichen ist, dass die tatsächliche Menge von Objekten in der Aufzählung nicht bekannt ist (im Voraus oder überhaupt nicht).
quelle
Sie können System.Linq verwenden.
Sie erhalten das Ergebnis '2'.
quelle
Wenn Sie über Ihre unmittelbare Frage hinausgehen (die gründlich verneint wurde), während Sie den Fortschritt während der Verarbeitung einer Aufzählung melden möchten, sollten Sie sich meinen Blog-Beitrag " Fortschritte bei Linq-Abfragen melden" ansehen .
Damit können Sie Folgendes tun:
quelle
Ich habe diese Methode in einer Methode verwendet, um den übergebenen
IEnumberable
Inhalt zu überprüfenInnerhalb einer Methode wie dieser:
quelle
bool hasContents = false; if (iEnum != null) foreach (object ob in iEnum) { hasContents = true; ... your code per ob ... }
.Dies hängt von der Version von .Net und der Implementierung Ihres IEnumerable-Objekts ab. Microsoft hat die IEnumerable.Count-Methode behoben, um nach der Implementierung zu suchen, und verwendet ICollection.Count oder ICollection <TSource> .Count. Weitere Informationen finden Sie hier https://connect.microsoft.com/VisualStudio/feedback/details/454130
Und unten ist die MSIL von Ildasm für System.Core, in der sich die System.Linq befindet.
quelle
Hier ist eine großartige Diskussion über die verzögerte Bewertung und die verzögerte Ausführung . Grundsätzlich müssen Sie die Liste materialisieren, um diesen Wert zu erhalten.
quelle
Das Ergebnis der Funktion IEnumerable.Count () ist möglicherweise falsch. Dies ist ein sehr einfach zu testendes Beispiel:
Das Ergebnis muss (7,7,3,3) sein, aber das tatsächliche Ergebnis ist (7,7,3,17).
quelle
Der beste Weg, den ich gefunden habe, ist zu zählen, indem ich ihn in eine Liste konvertiere.
quelle
Ich würde vorschlagen, ToList anzurufen. Ja, Sie führen die Aufzählung frühzeitig durch, haben jedoch weiterhin Zugriff auf Ihre Elementliste.
quelle
Möglicherweise wird nicht die beste Leistung erzielt, aber Sie können LINQ verwenden, um die Elemente in einer IEnumerable zu zählen:
quelle
Ich denke, der einfachste Weg, dies zu tun
Referenz: system.linq.enumerable
quelle
Ich benutze
IEnum<string>.ToArray<string>().Length
und es funktioniert gut.quelle
IEnum<string>.Count();
? " "?Ich verwende solchen Code, wenn ich eine Liste von Zeichenfolgen habe:
quelle