I’ve just run up against something in ‘Jetboard Joust’ whereby I needed to implement a custom generically-typed enumerator that I could enumerate through using the foreach statement along the lines of…
FooBar enumerator; foreach( Foo foo in enumerator ) { // do some stuff }
Unfortunately I found Microsoft’s documentation on this to be vague to the point of being misleading, and most of the StackOverflow answers weren’t much use either.
So here’s a simple example that defines a custom generic-type enumerator (implementing the IEnumerable and IEnumerator interfaces) that can be iterated through using the foreach statement. I’ve commented on the things that I found slightly odd – the main one being the fact that MoveNext() is called before the first object has been retrieved.
I’m using Xamarin and possibly Mono operates slightly differently than ‘native’ .net but it shouldn’t do.
Hope this helps someone…
using System.Collections.Generic; using System.Collections; namespace com.bitbull { public class FooEnumerator:IEnumerable,IEnumerator { #region properties private Foo[] foo=new Foo[24]; private int count; #endregion public FooEnumerator() { } /* * Called at the start of each foreach statement and it * would appear this is the best place to initialize your * counter. Note that, unintuitively, I start on -1 rather * than zero as MoveNext is called before the first object in * the enumeration is retrieved */ public IEnumerator GetEnumerator() { count=-1; return this; } /* * I'm not really sure why you need this here but * it won't compile without it */ IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } /* * Called each iteration of foreach BEFORE the current * object is retrieved. Unintuitively this means that if * you start your count on zero you will miss the first * object in your enumeration. * * Should return true or false depending on whether there * are further objects available to iterate through */ public bool MoveNext() { if (count>=foo.Length) { return false; } else { count++; return (count<foo.Length); } } /* * I am not entirely sure when this gets called but you * need to implement it! It doesn't seem to get called at * the start of each foreach statement which is what I * presumed would happen. I reset the counter here anyway * as it seems the sensible thing to do but this method * never seems to get called in my code. */ public void Reset() { count=-1; } /* * Returns the current object in the enumeration * called on each iteration of foreach */ public Foo Current { get { return foo[count]; } } /* * I'm not really sure why you need this here but * it won't compile without it */ object IEnumerator.Current { get{ return this.Current; } } /* * You need to implement this as well, again I'm not * really sure why this is really necessary. */ public void Dispose() { } } public class Foo { public Foo() { } } }