Julekalender 2004 om Whidbey


8. dec 2004 14:43

Dagens tip handler om de nye muligheder vedrørende iteratorer, der er kommet i C# 2.0.

Når man i C# itererer igennem en collection af objekter ved hjælp af et foreach statement, gør man (måske uden at vide det) brug af den pågældende collections implementation af interfacet System.Collection.IEnumerable. System.Collection.IEnumerable indeholder kun én metode, GetEnumerator(), som returnerer en enumerator (en System.Collection.IEnumerator) for den givne collection. Ved hjælp af enumeratorens MoveNext- og Reset-metode samt Current property kan man iterere igennem colletionens indhold.

Hidtil har man for at kunne foreach'e igennem sin collection skullet implementere System.Collection.IEnumerable på sin collection, samt lave en enumerator implementation som GetEnumerator kunne returnere. Med Whidbey bliver dette i C# en del simplere p.g.a. af det nye keyword yield. I Whidbey kan man i C# 'nøjes' med at implementere logikken til at iterere igennem den givne collection, man behøver ikke lave en ny klasse, der implementerer System.Collections.IEnumerable.

Derudover giver yield-konstruktionen nem mulighed for at have klasser som returnerer mange forskellige IEnumerator, alt efter hvordan man ønsker at løbe igennem en samling objekter.

Syntaks

Syntaksen for anvendelsen af yield er følgende

public class MyCollection : System.Collection.IEnumerable
{
  private object[] elements;
  
  // Implementation af Add, Remove, Count osv.

  public System.Collection.IEnumerator GetEnumerator()
  {
    // Loop igennem elementerne i MyCollection (Count i nedenstående er antallet af elementer i elements)
    for (int i = 0; i < this.Count; i++)
    {
      yield return elements[i];
    }
  }
}

Yield keywordet kan kun benyttes i metoder der returnerer System.Collections.IEnumerator eller System.Collections.IEnumerable.

Eksempel

Følgende lille demo benytter yield til at lave en enumerator, som kan iterere igennem rækken af fibonacci-tal op til et givet maksimum.
Fibonacci tal er forresten en talrække, hvor hvert tal i rækken er summen af de to forudgående. De to første tal undtaget, da vi ellers aldrig kommer igang :^)

public class TalRække
{
  public static System.Collections.IEnumerable Fibonacci(long maxVal)
  {
    // Fibonacci tallene er 0, 1, 1, 2, 3, 5, 8, ...

    long next = 1;
    long old = 0;
    
    // Det første tal i rækken er 0 
    yield return (long)0;
    
    while (next <= maxVal)
    {
      // Det næste tal i rækken er next (1, 1, 2, 3 osv.)
      yield return next;
      
      // Beregn næste tal i rækken (ny værdi til next)
      Calculate(ref next, ref old);
    }
  }

  private static void Calculate(ref long next, ref long old)
  {
    long temp = next;
    next += old;
    old = temp;
  }
}

I vores lille testapplikation kan vi afprøve ovenstående talrække og skrive noget passende ud i en lille messagebox.

System.Windows.Forms.MessageBox.Show(FormatOutput(TalRække.Fibonacci(42)));

Hvor FormatOutput er en lille hjælpe-metode, der foreach'er igennem en række tal.

private string FormatOutput(System.Collections.IEnumerable række)
{
  string s = "";

  foreach (long tal in række)
    s += tal.ToString() + "\r\n";
  
  return s;
}

Muligheden for at bruge yield er naturligvis ikke på linie med overgangen fra funktionsorienteret til objektorienteret programmering, men det er på den anden side denne slags syntaktiske sukker, som gør det lidt sjovere at kode.

Og det er i denne søde tid vigtigt nøje at overveje, hvilken slags sukker man indtager ;^)



Abonnér på mit RSS feed.   Læs også de øvrige indlæg i denne Blog.