Frage zu iEnumerable und Ienumerator
-
13-10-2019 - |
Frage
Ich verwende den folgenden Code, damit MyClass foreach verwendet werden kann. Aber ich bin ziemlich neu im Programmieren und habe Schwierigkeiten, den folgenden Code zu verstehen. Ich habe meine Probleme in den Kommentaren beschrieben. Ich wäre dankbar für die Bereitstellung von Informationen.
public class MyClass : IEnumerable<string>
{
//1) What is IEnumerator for?
// Whats the difference between IEnumerator and IEnumerable
public IEnumerator<string> GetEnumerator()
{
yield return "first";
yield return "second";
}
//2) What is it for? It just calls above method
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
//3) Lastly what benefits I have from implementing genetic interface
//IEnumerable<string> instead of just IEnumerable
Lösung
Was ist der Unterschied zwischen Ienumerator und Ienumerable?
Jasons Antwort ist gut, aber ich dachte, ich würde nur hinzufügen, wie ich darüber nachdenke. Stellen Sie sich vor, Sie haben eine Sequenz:
1, 1, 2, 3, 5, 8, 13, ...
Stellen Sie sich nun vor, Sie haben einen Pfeil, der auf eine Position dieser Sequenz zeigt:
1, 1, 2, 3, 5, 8, 13, ...
^
Ein "Pfeil" ist ein Objekt, das zwei Dinge tun kann. Erstens kann es Ihnen das geben, worauf es zeigt. Zweitens kann es sich auf die nächste Sache zeigen.
Ienumerator ist ein Pfeil. Es hat eine Eigenschaft, die Ihnen das gibt, worauf es zeigt. Es hat eine Methode, MoveNext (), die sich auf die nächste Sache zeigt.
Wie bekommt man überhaupt einen Pfeil? Sie brauchen eine Pfeilfabrik. Sie fragen die Fabrik um einen Pfeil, und es gibt Ihnen einen Pfeil, der auf das erste Element in der Sequenz hinweist.
Ienumerable ist eine Pfeilfabrik. Es hat eine Methode, Getenumerator, die Ihnen einen Pfeil zum ersten Element der Sequenz gibt.
Eine schöne Eigenschaft dieses Schemas ist, dass Sie mehrere Pfeile haben können, die auf verschiedene Orte in derselben Reihenfolge hinweisen.
Was sind die Vorteile der Implementierung der generischen Schnittstelle iEnumerable anstatt nur Ienumerable?
Angenommen, die Sequenz ist von Ganzzahlen. Wenn Sie implementieren IEnumerable
Dann, wenn du sagst
foreach(int x in mysequence)
Dies wird tatsächlich tun, ist, die INT in der Sequenz in Objekt zu konvertieren, die Ganzzahl zu dopfen und dann das Objekt sofort wieder zu Ganzzahl zu entbinden und jeder einzelnen Operation eine völlig unnötige Speicherzuweisung hinzuzufügen. Wenn der Compiler weiß, dass die Sequenz von Ganzzahlen besteht, kann er den unnötigen Boxvorgang überspringen.
Angenommen, die Sequenz besteht aus Saiten. Wenn Sie implementieren IEnumerable<string>
Dann können Sie sagen:
string first = mysequence.First();
Wenn Sie dies nicht tun, müssen Sie sagen
string first = (string)mysequence.First();
das ist unnötig und fehleranfällig. Anstatt den Compiler über eine Besetzung zu unterweisen, dass der Typ String ist, können Sie einfach Garantie dass der Typ anhand des Typsystems eine Zeichenfolge ist.
Andere Tipps
1) Was ist
IEnumerator
zum? Was ist der Unterschied zwischenIEnumerator
undIEnumerable
?
IEnumerator
ist eine Schnittstelle, die Methoden darstellt, mit denen Sie eine Sequenz aufzählen können. Der Unterschied zwischen IEnumerator
und IEnumerable
ist, dass ersterer den Vertrag für Objekte darstellt, mit denen Sie eine Sequenz aufzählen können, und der letztere den Vertrag für Objekte darstellt, die eine Sequenz sind, die aufgezählt werden kann.
public IEnumerator<string> GetEnumerator() {
yield return "first";
yield return "second";
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
2) Wofür ist es? Es werden nur die obige Methode aufgerufen.
Ersteres stellt eine Implementierung der Methode dar GetEnumerator
auf den Vertrag IEnumerable<string>
. Letzteres stellt eine explizite Implementierung der Methode dar GetEnumerator
auf den Vertrag IEnumerable
. Das Problem ist, dass beide Verträge eine Methode namens mit dem Namen haben GetEnumerator
Aber mit unterschiedlichen Rückgabetypen, damit eine Methode beide Verträge nicht gleichzeitig erfüllen kann (jede Klasse implementieren IEnumerable<T>
muss auch implementieren IEnumerable
wie IEnumerable<T> : IEnumerable
). Letzteres ruft die Implementierung von an IEnumerable<string>.GetEnumerator
Da ist dies eine vernünftige Implementierung, die eine zurückgibt IEnumerator
wie IEnumerator<string> : IEnumerator
.
3) Schließlich, welche Vorteile ich durch die Implementierung der generischen Schnittstelle habe
IEnumerable<string>
statt gerechtIEnumerable
?
Starke Typisierung. Sie wissen, dass die Elemente in einer Sequenz IEnumerable<string>
sind alle Fälle von String
Während Sie das nicht wissen für IEnumerable
und könnte am Ende versuchen, ein Element des letzteren in einen Fall von zu werfen String
wenn es nicht sein kann.
Dies ist die Erklärung für IEnumerable<T>
:
public interface IEnumerable<out T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
Sie haben keine Wahl, Sie haben Um die nicht generische ienumerable Schnittstelle zu implementieren. Sie erhalten einen Kompilierfehler, wenn Sie die Implementierung von iEnumerable.getenumerator () weglassen. Dies ist ein Gepäck, das aus den .NET 1.x -Tagen übrig geblieben ist, an denen Generika noch nicht verfügbar waren, und die Übergangszeit für .NET 2.0, in der die Interop mit .NET 1.x -Baugruppen unterstützt werden musste. Wir bleiben dabei.
1) Wofür ist Ienumerator?
Ienumerator ist der eigentliche Arbeitsteil mit MoveNext () und aktuellen Mitgliedern.
Was ist der Unterschied zwischen Ienumerator und Ienumerable
IEnumerable ist die Schnittstelle für eine Sammlung, um zu signalisieren, dass es einen Getenumerator () hat.
2) [nicht generischer Getenumerator] Wofür ist es? Es werden nur die obige Methode aufgerufen
Die nicht generische Methode ist nur für die Rückwärtskompatibilität vorhanden. Beachten Sie, dass es durch die Verwendung der expliziten Implementierung so weit wie möglich außer Sichtweite bewegt wird. Implementieren Sie es, weil Sie es müssen und dann vergessen.
3) Schließlich habe ich Vorteile, die ich durch die Implementierung der genetischen Schnittstelle iEnumerable statt nur iEnumerable habe
Wenn mit verwendet foreach
Der Adavantage ist klein, da Foreach die Schleifenvariable eintippt. Sie können Sie verwenden lassen var
im foreach:
foreach (var s in myClassInstance) // needs `IEnumerable<string>`
foreach (string s in myClassInstance) // works with `IEnumerable` as well
Aber mit IEnumerable<string>
Sie haben auch eine Typ-Sicherheit-Schnittstelle zu anderen Bereichen, vor allem Linq:
MyClass mc = new MyClass ();
string s = mc.FirstOrDefault();
GetEnumerator
Es gibt seit seiner Einführung von Generika in die Sprache, um den bereits bestehenden Code nicht zu brechen, die Standardmethode ruft zur generischen Implementierung auf.
Mit einer generischen Aufzählung muss der Verbraucher Ihrer Klasse nicht jedes Element beim Iterieren an die String geben.
In Bezug auf die 3. Frage (warum Generika verwenden?) Hier finden Sie einige Antworten:
Sollten wir eine generische Sammlung verwenden, um Sicherheit und Leistung zu verbessern?
Kurz gesagt, verwenden Sie jedes Mal generische Sammlungen, wenn Sie können.