Csharp/CSharp Tutorial/Data Structure/IEnumerator — различия между версиями
Admin (обсуждение | вклад) м (1 версия) |
|
(нет различий)
|
Текущая версия на 15:15, 26 мая 2010
Содержание
- 1 A simple example of an iterator.
- 2 Build your own IEnumerator/IEnumerable and use it in foreach loop
- 3 Circular Iterator
- 4 Define custom enumerators and use foreach to loop through
- 5 Implement IEnumerable and IEnumerator
- 6 Iterated values can be dynamically constructed.
- 7 Iteration Sample
- 8 Iterator Workflow
- 9 Use named iterators
- 10 Use the Enumerable pattern
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
- 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(); }
}</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 : ; <