By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
440,391 Members | 1,387 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 440,391 IT Pros & Developers. It's quick & easy.

syntax wonderings, iterator and IEnumerable

P: n/a
When creating multiple iterators, the original is defined as returning
IEnumerator, ie
public IEnumerator GetEnumerator() { yield x; ...}

whereas the additional ones are defined as returning IEnumerable, ie
public IEnumerable AnotherSortOrder() { yield x;....}

Any insights out there as to why the additional iteration methods did not
just return IEnumerator?
(its just a little confusing, hoping for some better insight)
Thanks
Mar 5 '07 #1
Share this Question
Share on Google+
2 Replies


P: n/a
Hello kenneth,

You should study the structure of the iteration interfaces - IEnumerable
is an interface that contains a method GetEnumerator, which in turn
returns an IEnumerator.

You'd normally have a structure like this:

class MyCollection : IEnumerable {
public IEnumerator GetEnumerator() {
// This method is implemented to satisfy the requirements
// of the IEnumerable interface
}
}

The reason you do this is because you would like to use an instance of
your class for iteration, like this:

MyCollection coll = ...;
foreach (Item item in coll) ...

As you can see, the iteration works directly with your instance, which is
because the IEnumerable interface is implemented. Obviously, if you want
to do other iterations, you'll have to have an IEnumerable interface for
these as well, so you do:

class MyCollection : IEnumerable {
...
public IEnumerable AnotherSortOrder() { ... }
}

MyCollection coll = ... ;
foreach (Item item in coll.AnotherSortOrder()) ...

In this case you're calling a method to get the iteration interface - of
course it still has to be the right type.

So the short summary is: the foreach wants to have an IEnumerable to
iterate over. Your class can implement that interface itself and/or it can
contain methods returning that type. It depends on your purpose and on the
syntax you want to use for the iteration.
Oliver Sturm
--
http://www.sturmnet.org/blog
Mar 6 '07 #2

P: n/a

Ok, I had tricked myself a bit.
I was playing with IEnumerator and manually looping with plain for() and
while() loops. With them, I was able to create multiple functions returning
IEnumerator, to return a collection in different iteration orders.
i.e. IEnumerator F1() { //loop forwards }
IEnumerator F2() { //loop backwards }
What I didn't do was try using these functions with a foreach().... which I
found would not compile.

It took some playing and looking, but now I see how I can implement multiple
iteration methods using just IEnumerable and IEnumerator.
Each iteration method will have a function that returns an IEnumerable
object, and a private embedded class that implements that object. i.e.
public IEnumerable Reverse()
{
return new _Reverse(this);
}
private class _Reverse : IEnumerable
{
...
public virtual IEnumerator GetEnumerator()
...
}

Then the foreach() loop would look like:
foreach( String s in Coll.Reverse())
versus the standard call:
foreach( String s in Coll)

So now I understand my original question, which was when using iterators
(with their yield returns), why did additional iteration methods return the
IEnumerable method while the first was (seemingly) returning IEnumerator.
i.e. public IEnumerator GetEnumerator()
{
yield 1; yield 2; yield 3;
}
public IEnumerable Reverse()
{
yield 3; yield 2; yield 1;
}
But, having two differnet function return types around the yield returns
statements still makes me cringe.
Thanks.

Following is a little code that may help someone else get a better handle on
this too. I snagged part from a couple of different locations, and added
some myself. :) <will run in snippet compiler>
using System;
using System.Collections;
//Class ItemCollection implements IEnumerable interface
class ItemCollection : IEnumerable
{
String[] itemId ;

//Constructor to create and populate itemId String array
public ItemCollection( int noOfItem )
{
itemId = new String[noOfItem] ;
for(int i = 0; i < itemId.Length; i ++ )
{
itemId[i] = i.ToString();
}
}
//Implementation of method GetEnumerator of IEnumerable interface
public virtual IEnumerator GetEnumerator()
{
return new ItemIterator(this);
}
//Inner class ItemIterator, implements IEnumerator
public class ItemIterator : IEnumerator
{
//Declare a variable of type ItemCollection,
//to keep reference to enclosing class instance
private ItemCollection itemCollection;
//Declare a integer pointer and Set to -1, so that
//first call to MoveNext moves the enumerator over
//the first element of the collection.
private int index = -1 ;

//Pass an instance of enclosing class
public ItemIterator(ItemCollection ic)
{
//Save enclosing class reference
itemCollection = ic ;
}

//After an enumerator is created or after a Reset,
//an enumerator is positioned before the first element
//of the collection, and the first call to MoveNext
//moves the enumerator over the first element of the
//collection.
public bool MoveNext()
{
index++ ;
if( index < itemCollection.itemId.Length )
{
return true ;
}
else
{
index = -1;
return false;
}
}
//Return the current object, in our case Item Id string
//from itemId[] array. Throws InvalidOperationException exception
//if index pointing to wrong position
public object Current
{
get
{
if( index <= -1 )
{
throw new InvalidOperationException() ;
}
return itemCollection.itemId[index];
}
}

//Reset pointer to -1
public void Reset()
{
index = -1;
}
}

//Implementation of method GetEnumerator of IEnumerable interface
public virtual IEnumerator GoBackwards()
{
return new ItemIterator2(this);
}
//Inner class ItemIterator, implements IEnumerator
public class ItemIterator2 : IEnumerator
{
//Declare a variable of type ItemCollection,
//to keep reference to enclosing class instance
private ItemCollection itemCollection;
//Declare a integer pointer and Set to -1, so that
//first call to MoveNext moves the enumerator over
//the first element of the collection.
private int index = int.MaxValue ;

//Pass an instance of enclosing class
public ItemIterator2(ItemCollection ic)
{
//Save enclosing class reference
itemCollection = ic ;
}

//After an enumerator is created or after a Reset,
//an enumerator is positioned before the first element
//of the collection, and the first call to MoveNext
//moves the enumerator over the first element of the
//collection.
public bool MoveNext()
{
if(index == int.MaxValue)
index = itemCollection.itemId.Length;

index-- ;
if( index < itemCollection.itemId.Length &&
index >= 0)
{
return true ;
}
else
{
index = -1;
return false;
}
}
//Return the current object, in our case Item Id string
//from itemId[] array. Throws InvalidOperationException exception
//if index pointing to wrong position
public object Current
{
get
{
if( index >= itemCollection.itemId.Length )
{
throw new InvalidOperationException() ;
}
return itemCollection.itemId[index];
}
}

//Reset pointer to past end
public void Reset()
{
index = int.MaxValue;
}
}
// try a 2nd enumerable
public IEnumerable Reverse()
{
return new _Reverse(this);
}

private class _Reverse : IEnumerable
{
private ItemCollection _this;

public _Reverse(ItemCollection x)
{
_this = x;
}

//Implementation of method GetEnumerator of IEnumerable interface
public virtual IEnumerator GetEnumerator()
{
return new ItemIterator2(_this);
}
}

public class SkipEnumerator : IEnumerable, IEnumerator
{
IEnumerator ienumerator_;
int skip_;
bool start_ = true;

public SkipEnumerator(IEnumerable ienumerable, int skip)
{
ienumerator_ = ienumerable.GetEnumerator();
skip_ = skip;
}

#region IEnumerable

public IEnumerator GetEnumerator()
{
return this;
}

#endregion

#region IEnumerator

public bool MoveNext()
{
if (start_)
{
for (int i = 0; i < skip_; i++)
ienumerator_.MoveNext();
start_ = false;
}

return ienumerator_.MoveNext();
}

public object Current
{
get
{
return ienumerator_.Current;
}
}

public void Reset()
{
start_ = true;
ienumerator_.Reset();
}

#endregion
}

public static int Main(String[] args)
{
//Instantiate the collection
ItemCollection itemCol = new ItemCollection(10);

//Iterate the collection with various looping construct
//provided in c#

//HERE IS YOUR BASIC FOREACH
Console.WriteLine("1. Iteration using foreach loop:");
foreach( String itemIdStr in itemCol)
{
Console.Write(itemIdStr + " " );
}

// MANUALLY USING A FOR LOOP
Console.WriteLine("\n\n2. Iteration using for loop:");
for(IEnumerator ie = itemCol.GetEnumerator() ;
ie.MoveNext();)
{
Console.Write(ie.Current + " " );
}

// MANUALLY USING A WHILE LOOP
Console.WriteLine("\n\n3. Iteration using while loop:");
IEnumerator ie1 = itemCol.GetEnumerator();
while(ie1.MoveNext())
{
Console.Write(ie1.Current + " ");
}

// CREATING A SECOND FUNCTION RETURNING AN IENUMERATOR, MANUALLY
// CALLING IT. CANT USE WITH A FOREACH!!!
Console.WriteLine("\n\n4. Iteration backwards using for loop:");
for(IEnumerator ie = itemCol.GoBackwards() ;
ie.MoveNext();)
{
Console.Write(ie.Current + " " );
}

// CREATING A SECOND FUNCTION RETURNING AN IENUMERATOR, MANUALLY
// CALLING IT. CANT USE WITH A FOREACH!!!
Console.WriteLine("\n\n5. Iteration backwards using while loop:");
ie1 = itemCol.GoBackwards();
while(ie1.MoveNext())
{
Console.Write(ie1.Current + " ");
}

// CREATING A SECOND FUNCTION RETURNING AN IENUMERABLE. THEN USING
// A PRIVATE CLASS TO IMPLEMENT IT.
// CALLING USING A FOREACH!!!
Console.WriteLine("\n\n6. Iteration backwards using foreach loop:");
foreach( String itemIdStr in itemCol.Reverse())
{
Console.Write(itemIdStr + " " );
}

// ANOTHER WAY TO GET ADDITIONAL ITERATION METHODS
Console.WriteLine("\n\n7. Iteration skip using foreach loop:");
foreach( String itemIdStr in new SkipEnumerator(itemCol, 2))
{
Console.Write(itemIdStr + " " );
}

Console.ReadLine();
return 0;
}
}
Mar 6 '07 #3

This discussion thread is closed

Replies have been disabled for this discussion.