Csharp/CSharp Tutorial/Data Structure/IEnumerator — различия между версиями
Admin (обсуждение | вклад) м (1 версия) |
Admin (обсуждение | вклад) м (1 версия) |
(нет различий)
|
Текущая версия на 12: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.
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 : ; <