472,345 Members | 1,521 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,345 software developers and data experts.

syntax wonderings, iterator and IEnumerable

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
2 4159
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

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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: Niall | last post by:
Ok, maybe this is getting too lazy and too demanding, but hey, I thought I'd see what people thought about it. Would anyone else find a syntax...
2
by: Peter Rilling | last post by:
One nice thing about collections and arrays is that they implement the IEnumerator and IEnumerable interfaces which allow for more then one...
18
by: Marco | last post by:
I need to get a iterator from any generic collection. public class .... GetIterator(Object collection) { ..... }
9
by: Anthony Bouch | last post by:
Everything I know about looping structures says to be careful about expressions that need to be evaluated again and again for each test/increment...
14
by: shawnk | last post by:
I searched the net to see if other developers have been looking for a writable iterator in C#. I found much discussion and thus this post. ...
3
by: Wiktor Zychla [C# MVP] | last post by:
since generics allow us to implement several IEnumerable<T> interfaces on a single class, I think that "foreach" should somehow reflect that. ...
2
by: Andrew Matthews | last post by:
Hi All, I have an issue that I can't solve with the following (cleaned up) piece of code. What I've seen in the VS 2005 debugger is that the...
0
by: Tony Johansson | last post by:
Hello! I have noticed that I can use iterator in a method and return an IEnumerable like this public IEnumerable<TReverse() { for (int i =...
0
by: jehugaleahsa | last post by:
Hello: Yesterday, I encountered an interesting side-effect of iterators. Even though the code looked fine, it actually was completely wrong. See...
0
by: concettolabs | last post by:
In today's business world, businesses are increasingly turning to PowerApps to develop custom business applications. PowerApps is a powerful tool...
0
by: teenabhardwaj | last post by:
How would one discover a valid source for learning news, comfort, and help for engineering designs? Covering through piles of books takes a lot of...
0
by: Naresh1 | last post by:
What is WebLogic Admin Training? WebLogic Admin Training is a specialized program designed to equip individuals with the skills and knowledge...
0
by: antdb | last post by:
Ⅰ. Advantage of AntDB: hyper-convergence + streaming processing engine In the overall architecture, a new "hyper-convergence" concept was...
0
by: Matthew3360 | last post by:
Hi there. I have been struggling to find out how to use a variable as my location in my header redirect function. Here is my code. ...
2
by: Matthew3360 | last post by:
Hi, I have a python app that i want to be able to get variables from a php page on my webserver. My python app is on my computer. How would I make it...
0
by: Arjunsri | last post by:
I have a Redshift database that I need to use as an import data source. I have configured the DSN connection using the server, port, database, and...
0
hi
by: WisdomUfot | last post by:
It's an interesting question you've got about how Gmail hides the HTTP referrer when a link in an email is clicked. While I don't have the specific...
0
by: Matthew3360 | last post by:
Hi, I have been trying to connect to a local host using php curl. But I am finding it hard to do this. I am doing the curl get request from my web...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.