Foreach kann Zuweisungen verursachen, aber zumindest in den neueren Versionen .NET und Mono, tut es nicht, wenn Sie mit den konkreten System.Collections.Generic
Typen oder Arrays zu tun haben. Ältere Versionen dieser Compiler (z. B. die von Unity3D bis 5.5 verwendete Version von Mono) generieren immer Zuweisungen.
Der C# -Compiler verwendet duck typing, um nach einer GetEnumerator()
-Methode zu suchen, und verwendet diese, wenn möglich. Die meisten GetEnumerator()
Methoden auf System.Collection.Generic
Typen haben GetEnumerator() -Methoden, die Strukturen zurückgeben, und Arrays werden speziell behandelt. Wenn Ihre GetEnumerator()
-Methode nicht zuweist, können Sie normalerweise Zuweisungen vermeiden.
Allerdings werden Sie immer eine Zuteilung erhalten, wenn Sie mit einer der Schnittstellen zu tun IEnumerable
, IEnumerable<T>
, IList
oder IList<T>
. Selbst wenn Ihre implementierende Klasse eine Struktur zurückgibt, wird die Struktur eingerahmt und in IEnumerator
oder IEnumerator<T>
umgewandelt, was eine Zuweisung erfordert.
HINWEIS: Da 5.5 Unity zu C# 6 aktualisiert, kenne ich keine aktuellen Compiler Version, die noch diese zweite Zuordnung hat.
Es gibt eine zweite Zuweisung, die ein wenig komplizierter zu verstehen ist. Nehmen Sie diese foreach-Schleife:
List<int> valueList = new List<int>() { 1, 2 };
foreach (int value in valueList) {
// do something with value
}
Bis C# 5.0, dehnt es sich um so etwas wie dies (mit gewissen kleinen Unterschieden):
List<int>.Enumerator enumerator = valueList.GetEnumerator();
try {
while (enumerator.MoveNext()) {
int value = enumerator.Current;
// do something with value
}
}
finally {
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
Während List<int>.Enumerator
eine Struktur ist, und muss nicht sein auf dem Heap zugewiesen, die Besetzung enumerator as System.IDisposable
Boxen die Struktur, die eine Zuordnung ist. Die Spezifikation änderte sich mit C# 5.0 und verbot die Zuweisung, aber .NET broke the spec und optimierte die Zuweisung früher.
Diese Zuweisungen sind äußerst gering. Beachten Sie, dass sich eine Zuweisung von einem Speicherverlust unterscheidet, und bei der Garbage Collection müssen Sie sich im Allgemeinen keine Gedanken darüber machen. Es gibt jedoch einige Szenarien, in denen Sie sich selbst um diese Zuordnungen kümmern. Ich arbeite an Unity3D und bis 5.5 konnten wir keine Zuteilungen in Operationen vornehmen, die bei jedem Spielframe passieren, denn wenn der Garbage Collector ausgeführt wird, bekommen Sie einen spürbaren Ruck.
Beachten Sie, dass Foreach-Schleifen in Arrays speziell behandelt werden und nicht Dispose aufrufen müssen. Soweit ich das beurteilen kann, hat foreach niemals zugewiesen, wenn Arrays durchlaufen werden.
a) Dies ist ein Implementierungsdetail. Diese sind irrelevant. b) Der GC existiert. –
Ich denke, das Hauptproblem mit einzelnen Enumerator wäre Thread-Sicherheit. – volpav
Dies ist nicht auf 'foreach()' beschränkt. Die ganze Idee eines GC ist, dass kleine, kurzlebige Objekte sehr billig sind. Wir "verschwenden" sie ständig, wie in 'text = text.ToLower();'. Mach dir keine Sorgen darüber. Die meisten Wiederverwendungsschemata erweisen sich als kostspieliger. –