nicht allzu lange Zeit, bevor ich entdeckt habe, dass neues dynamic
Schlüsselwort nicht gut mit dem C# 's foreach
Anweisung funktioniert:C# 4.0 ‚dynamisch‘ und foreach-Anweisung
using System;
sealed class Foo {
public struct FooEnumerator {
int value;
public bool MoveNext() { return true; }
public int Current { get { return value++; } }
}
public FooEnumerator GetEnumerator() {
return new FooEnumerator();
}
static void Main() {
foreach (int x in new Foo()) {
Console.WriteLine(x);
if (x >= 100) break;
}
foreach (int x in (dynamic)new Foo()) { // :)
Console.WriteLine(x);
if (x >= 100) break;
}
}
}
Ich habe, dass über die iteriert erwartet dynamic
Variable sollte vollständig funktionieren, als ob der Typ der Auflistungsvariablen zur Kompilierzeit bekannt ist. Ich habe entdeckt, dass die zweite Schleife tatsächlich so ausgesehen, wenn kompiliert wird:
foreach (object x in (IEnumerable) /* dynamic cast */ (object) new Foo()) {
...
}
und jeder Zugriff auf die x-Variable Ergebnisse mit der dynamischen Lookup/cast so C# ignoriert, dass ich angeben habe die richtigen x
' s Typ in der Foreach-Anweisung - das war ein bisschen überraschend für mich ... Und auch, C# -Compiler vollständig ignoriert diese Sammlung von dynamisch typisierte Variable Mai implementiert IEnumerable<T>
Schnittstelle!
Die vollständige foreach
Anweisung Verhalten ist in der C# 4.0-Spezifikation beschrieben 8.8.4 Die Foreach-Anweisung Artikel.
Aber ... Es ist durchaus möglich, das gleiche Verhalten zur Laufzeit zu implementieren! Es ist möglich, eine zusätzliche CSharpBinderFlags.ForEachCast
Flagge, korrigieren Sie den ausgestrahlten Code sieht aus wie hinzuzufügen:
foreach (int x in (IEnumerable<int>) /* dynamic cast with the CSharpBinderFlags.ForEachCast flag */ (object) new Foo()) {
...
}
Und fügen Sie einige zusätzliche Logik zu CSharpConvertBinder
:
- Wrap
IEnumerable
Sammlungen undIEnumerator
‚s zuIEnumerable<T>
/IEnumerator<T>
. - Wrap Collections implementiert
Ienumerable<T>
/IEnumerator<T>
nicht, um diese Schnittstellen zu implementieren.
So heute foreach
Anweisung iteriert über dynamic
völlig verschieden von Iterieren statisch bekannter Sammlung Variable über und ignoriert vollständig die Typinformationen, vom Benutzer festgelegt. All das führt zu dem unterschiedlichen Iterationsverhalten (IEnumarble<T>
-implementierende Sammlungen wird nur als IEnumerable
-implementierend iteriert) und mehr als 150x
Verlangsamung beim Iterieren über dynamic
. Einfache Lösung führt zu einer viel besseren Leistung:
foreach (int x in (IEnumerable<int>) dynamicVariable) {
Aber warum sollte ich Code so schreiben?
Es ist sehr schön zu sehen, dass manchmal C# 4.0 dynamic
Werke vollständig gleich, wenn der Typ zum Zeitpunkt der Kompilierung bekannt sein wird, aber es ist leider sehr zu sehen, dass dynamic
funktioniert völlig anders, wo es kann das gleiche wie statisch typisierte Code funktioniert .
Also meine Frage ist: Warum funktioniert foreach
über dynamic
funktioniert anders als foreach
über etwas anderes?
Ich interessiere mich sehr für das Verhalten, das ist völlig anders als statische 'foreach'! Das Leistungsproblem ist nur das Ergebnis von falschem Verhalten. Warum "IEnumerable" + dynamische Konvertierung verwenden, wobei statisch bekannt ist, dass "forech" über die Ganzzahl-Sequenz iteriert? – ControlFlow