Es gibt ja doch die eine oder andere spannende Neuerung in C# 2.0 - allen voran natürlich Generics.
Ebenfalls durchaus nützlich sind die neuen
Iteratoren.
Was war...
Die foreach-Schleife gehörte auch schon in C# 1.0 zu den beliebtesten Schleifen-Typen. Um diese
auf eigene Datentypen anwenden zu können, wurde überlicherweise das IEnumerable-Interface implementiert werden;
dies sah dann so ähnlich aus:
public class BuddyList : IEnumerable
{
string[] _buddies = { "Patrick", "Joel", "Daniel", "Andrea" };
#region IEnumerable-Members
public IEnumerator GetEnumerator()
{
return new BuddyEnumerator(this);
}
#endregion
class BuddyEnumerator : IEnumerator
{
BuddyList _buddyList;
int _current;
public BuddyEnumerator(BuddyList buddyList)
{
_buddyList = buddyList;
_current = -1;
}
#region IEnumerator-Members
void IEnumerator.Reset()
{
_current = -1;
}
void IEnumerator.MoveNext()
{
return (++_current < _buddyList.Length);
}
object IEnumeratorCurrent
{
get
{
if(_current == -1)
throw new InvalidOperationException();
return _buddyList[_current];
}
}
#endregion
}
}
Also - eine Klasse BuddyList, die das Interface IEnumerable implementiert. IEnumerable verlangt nach der Methode
"GetEnumerator" welche wiederum eine IEnumerator-Implementation zurückgibt - und das ist genau, was die foreach-Schleife
benötigt, um funktionieren zu können.
Die IEnumerator-Implementation wurde hier in einer geschachtelten Klasse BuddyEnumerator implementiert. Verlangt
werden die Methoden Reset() und MoveNext() sowie das Property Current. Offensichtlich nicht sehr kompliziert, aber doch
einen ganzen Haufen an Code (und potenziellen Fehlern) für eine eigentlich so einfache Sache.
Schöne neue Welt!C# 2.0 bietet hier eine viel einfachere und elegantere Methode, um dieses Unterfangen zu realisieren. Voraus gleich der Code:
public class BuddyList : IEnumerable<string>
{
string[] _buddies = { "Patrick", "Joel", "Daniel", "Andrea" };
#region IEnumerable<string> Members
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
for (int i = 0; i < _buddies.Length; i++)
{
yield return _buddies[i];
}
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((IEnumerable<string>) this).GetEnumerator();
}
#endregion
}Das sieht doch schon etwas übersichtlicher aus. Wiederum wird also das Interface IEnumerable implementiert
(das hier das generische Pendant benutzt wird, tut nichts zur Sache). In der ersten GetEnumerator-Methode fällt
die Anweisung "yield" sofort ins Auge. Diese erzeugt für uns quasi automatisch die geschachtelte Klasse aus dem
C# 1.0-Beispiel.
Damit wird der Code viel übersichtlicher und weniger aufgebläht als mit den ganzen IEnumerator-Implementierungen.
Es ist auch möglich, laufende Iterationen zu unterbrechen - hierfür wird die Anweisung "yield break;" verwendet:
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
for (int i = 0; i < _buddies.Length; i++)
{
yield return _buddies[i];
// zeige nur 4 buddies
if(i > 3)
yield break;
}
}
Die kleine Beispiel-Applikation gibts zum download:
Iterator.zip (582,07 KB)