Csharp/CSharp Tutorial/Data Structure/IEnumerator

Материал из .Net Framework эксперт
Перейти к: навигация, поиск

A simple example of an iterator.

<source lang="csharp">using System; using System.Collections;

class MyClass {

 char[] chrs = { "A", "B", "C", "D" }; 

 public IEnumerator GetEnumerator() { 
   foreach(char ch in chrs) 
     yield return ch; 
 } 

}

class MainClass {

 public static void Main() { 
   MyClass mc = new MyClass(); 

   foreach(char ch in mc) 
     Console.Write(ch + " "); 

   Console.WriteLine(); 
 } 

}</source>

A B C D

Build your own IEnumerator/IEnumerable and use it in foreach loop

<source lang="csharp">using System; using System.Collections; class LetterEnumerator : IEnumerator {

  string[] letters;
  int Position = -1;
  public LetterEnumerator(string[] theletters) 
  {
     letters = new string[theletters.Length];
     for (int i = 0; i < theletters.Length; i++)
        letters[i] = theletters[i];
  }
  public object Current                    
  {
     get { return letters[Position]; }
  }
  public bool MoveNext()                   
  {
     if (Position < letters.Length - 1){ 
        Position++; return true; 
     }
     else
        return false;
  }
  public void Reset()                      
  {
     Position = -1;
  }

} class LetterList : IEnumerable {

  string[] letters = { "A", "B", "C" };
  public IEnumerator GetEnumerator()
  {
     return new LetterEnumerator(letters);
  }

} class MainClass {

  static void Main()
  {
     LetterList mc = new LetterList();
     foreach (string l in mc)
        Console.WriteLine("{0} ", l);
  }

}</source>

A
B
C

Circular Iterator

<source lang="csharp">/* Quote from Accelerated C# 2005

  1. By Trey Nash
  2. ISBN: 1-59059-717-6
  3. 432 pp.
  4. Published: Aug 2006
  • /

using System; using System.Collections; using System.Collections.Generic; public class MainClass {

   static void Main() {
       LinkedList<int> intList = new LinkedList<int>();
       for( int i = 1; i < 6; ++i ) {
           intList.AddLast( i );
       }
       CircularIterator<int> iter = new CircularIterator<int>(intList, intList.First);
       int counter = 0;
       foreach( int n in iter ) {
           Console.WriteLine( n );
           if( counter++ == 100 ) {
               iter.Stop();
           }
       }
   }

} public class CircularIterator<T> : IEnumerable<T> {

   public CircularIterator( LinkedList<T> list, LinkedListNode<T> start ) {
       enumerator = CreateEnumerator( list, start, false ).GetEnumerator();
       enumType = enumerator.GetType();
   }
   public void Stop() {
       enumType.GetField("stop").SetValue( enumerator, true );
   }
   private IEnumerator<T> enumerator;
   private Type enumType;
   private IEnumerable<T> CreateEnumerator( LinkedList<T> list, LinkedListNode<T> start, bool stop ) {
       LinkedListNode<T> current = null;
       do {
           if( current == null ) {
               current = start;
           } else {
               current = current.Next;
               if( current == null ) {
                   current = start;
               }
           }
           yield return current.Value;
       } while( !stop );
   }
   public IEnumerator<T> GetEnumerator() {
       return enumerator;
   }
   IEnumerator IEnumerable.GetEnumerator() {
       return GetEnumerator();
   }

}</source>

1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1
2
3
4
5
1

Define custom enumerators and use foreach to loop through

<source lang="csharp">// Code revised from //A Programmer"s Introduction to C# 2.0, Third Edition using System; using System.Collections; // Note: This class is not thread-safe public class IntList: IEnumerable {

   int[] values = new int[10];
   int allocated = 10;
   int count = 0;
   int revision = 0;
   
   public void Add(int value)
   {
       // reallocate if necessary
       if (count + 1 == allocated)
       {
           int[] newValues = new int[allocated * 2];
           for (int index = 0; index < count; index++)
           {
               newValues[index] = values[index];
           }
           allocated *= 2;
       }        
       values[count] = value;
       count++;
       revision++;
   }
   
   public int Count
   {
       get
       {
           return(count);
       }
   }
   
   void CheckIndex(int index)
   {
       if (index >= count)
       throw new ArgumentOutOfRangeException("Index value out of range");
   }
   
   public int this[int index]
   {
       get
       {
           CheckIndex(index);
           return(values[index]);
       }
       set
       {
           CheckIndex(index);
           values[index] = value;
           revision++;
       }
   }
   
   public IEnumerator GetEnumerator()
   {
       return(new IntListEnumerator(this));
   }
   
   internal int Revision
   {
       get
       {
           return(revision);
       }
   }

} class IntListEnumerator: IEnumerator {

   IntList    intList;
   int revision;
   int index;
   
   internal IntListEnumerator(IntList intList)
   {
       this.intList = intList;
       Reset();
   }
   
   public bool MoveNext()
   {
       index++;
       if (index >= intList.Count)
       return(false);
       else
       return(true);
   }
   
   public object Current
   {
       get
       {
           if (revision != intList.Revision)
           throw new InvalidOperationException("Collection modified while enumerating.");
           return(intList[index]);
       }
   }
   
   public void Reset()
   {
       index = -1;
       revision = intList.Revision;
   }

} class MainClass {

   public static void Main()
   {
       IntList list = new IntList();
       
       list.Add(1);
       list.Add(55);
       list.Add(43);
       
       foreach (int value in list)
       {
           Console.WriteLine("Value = {0}", value);
       }
       
       foreach (int value in list)
       {
           Console.WriteLine("Value = {0}", value);
           list.Add(124);
       }
   }

}</source>

Value = 1
Value = 55
Value = 43
Value = 1
Unhandled Exception: System.InvalidOperationException: Collection modified while enumerating.
   at IntListEnumerator.get_Current()
   at MainClass.Main()

Implement IEnumerable and IEnumerator

<source lang="csharp">using System; using System.Collections;

class MyClass : IEnumerator, IEnumerable {

 char[] chrs = { "A", "B", "C", "D" }; 
 int index = -1; 

 // Implement IEnumerable. 
 public IEnumerator GetEnumerator() { 
   return this; 
 } 

 // The following methods implement IEnumerator. 

 // Return the current object. 
 public object Current { 
   get { 
     return chrs[index]; 
   } 
 } 

 // Advance to the next object.  
 public bool MoveNext() { 
   if(index == chrs.Length-1) { 
     Reset(); // reset enumerator at the end. 
     return false; 
   } 
    
   index++; 
   return true; 
 } 
   
 // Reset the enumerator to the start. 
 public void Reset() { 
   index = -1; 
 }  

}

class MainClass {

 public static void Main() { 
   MyClass mc = new MyClass(); 

   // Display the contents of mc. 
   foreach(char ch in mc) 
     Console.Write(ch + " "); 

   Console.WriteLine(); 

   // Display the contents of mc, again. 
   foreach(char ch in mc) 
     Console.Write(ch + " "); 

   Console.WriteLine(); 
 } 

}</source>

A B C D
A B C D

Iterated values can be dynamically constructed.

<source lang="csharp">using System; using System.Collections;

class MyClass {

 char ch = "A"; 

 public IEnumerator GetEnumerator() { 
   for(int i=0; i < 26; i++) 
     yield return (char) (ch + i); 
 } 

}

class MainClass {

 public static void Main() { 
   MyClass mc = new MyClass(); 

   foreach(char ch in mc) 
     Console.Write(ch + " "); 

   Console.WriteLine(); 
 } 

}</source>

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

Iteration Sample

<source lang="csharp">using System; using System.Collections; using System.ruponentModel;

       class IterationSampleIterator : IEnumerator{
           public IterationSample parent;
           public int position;
           internal IterationSampleIterator(IterationSample parent){
               this.parent = parent;
               position = -1;
           }
           public bool MoveNext(){
               if (position != parent.values.Length){
                   position++;
               }
               return position < parent.values.Length;
           }
           public object Current{
               get{
                   if (position == -1 || position == parent.values.Length){
                       throw new InvalidOperationException();
                   }
                   int index = (position + parent.startingPoint);
                   index = index % parent.values.Length;
                   return parent.values[index];
               }
           }
           public void Reset(){
               position = -1;
           }
       }
       class IterationSample : IEnumerable{
           public object[] values;
           public int startingPoint;
   
           public IterationSample(object[] values, int startingPoint){
               this.values = values;
               this.startingPoint = startingPoint;
           }
   
           public IEnumerator GetEnumerator()
           {
               return new IterationSampleIterator(this);
           }
           public static void Main(){
               object[] values = { "a", "b", "c", "d", "e" };
               IterationSample collection = new IterationSample(values, 3);
               foreach (object x in collection){
                   Console.WriteLine(x);
               }
           }
       }</source>

Iterator Workflow

<source lang="csharp">using System;

   using System.Collections.Generic;
   using System.ruponentModel;
   class IteratorWorkflow
   {
       static readonly string Padding = new string(" ", 30);
       static IEnumerable<int> GetEnumerable(){
           Console.WriteLine(Padding);
           for (int i = 0; i < 3; i++){
               Console.WriteLine("{0}About to yield {1}", Padding, i);
               yield return i;
               Console.WriteLine("{0}After yield", Padding);
           }
           Console.WriteLine(Padding);
           yield return -1;
       }
       static void Main(){
           IEnumerable<int> iterable = GetEnumerable();
           IEnumerator<int> iterator = iterable.GetEnumerator();
           while (true){
               bool result = iterator.MoveNext();
               Console.WriteLine(result);
               if (!result)
               {
                   break;
               }
               Console.WriteLine(iterator.Current);
           }
       }
   }</source>

Use named iterators

<source lang="csharp">using System; using System.Collections;

class MyClass {

 char ch = "1"; 

 public IEnumerable MyItr(int end) { 
   for(int i=0; i < end; i++) 
     yield return (char) (ch + i); 
 } 

}

class MainClass {

 public static void Main() { 
   MyClass mc = new MyClass(); 

   foreach(char ch in mc.MyItr(7)) 
     Console.Write(ch + " "); 

   Console.WriteLine("\n"); 

 } 

}</source>

1 2 3 4 5 6 7

Use the Enumerable pattern

<source lang="csharp">using System; using System.Collections;

class MyClass {

 char ch = "1"; 

 public IEnumerable MyItr(int begin, int end) { 
   for(int i=begin; i < end; i++) 
     yield return (char) (ch + i); 
 } 

}

class MainClass {

 public static void Main() { 
   MyClass mc = new MyClass(); 

   foreach(char ch in mc.MyItr(5, 12)) 
     Console.Write(ch + " "); 

   Console.WriteLine(); 
 } 

}</source>

6 7 8 9 : ; <