Csharp/CSharp Tutorial/Data Structure/IEnumerator

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

A simple example of an iterator.

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(); 
  } 
}
A B C D

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

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);
   }
}
A
B
C

Circular Iterator

/*
Quote from
Accelerated C# 2005
# By Trey Nash
# ISBN: 1-59059-717-6
# 432 pp.
# 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();
    }
}
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

// 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);
        }
    }
}
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

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(); 
  } 
}
A B C D
A B C D

Iterated values can be dynamically constructed.

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(); 
  } 
}
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

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);
                }
            }
        }

Iterator Workflow

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);
            }
        }
    }

Use named iterators

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"); 
 
  } 
}
1 2 3 4 5 6 7

Use the Enumerable pattern

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(); 
  } 
}
6 7 8 9 : ; <