Thanks for the elaborate reply, but maybe IEnumerable
is the wrong thing here anyway. You reply:
IEnumerator is something like a /Generator/, right?
It's an implementation of CLU's iterator feature, but generator is
another name for it.
A big advantage of generators is that you can recycle
them and use them in the fashion of command-line pipes,
like this:
RandomNumberGen erator | FilterPrimeNumb ersGenerator | MultiplyBy4...
I assumed I can do the same with IEnumerable, but it
seems that it is a lot more tricky than I thought.
The key is that I (wrongly) guessed that /yield/ is just a mechanism
for marking the spot where a function returns this time
and will continue next time. /foreach/ simply calls the
function embodying the /yield/. This can't be true, I guess.
Here is an illustration:
int foo()
{
int counter = 0;
yield counter++;
}
Multiple clients can call foo, and the
spot where to continue has to be remembered for each
new caller. This means that the first call to /foo/
somehow instantiates a new environment for that
particular foo(), complete with its own version
of /counter/ (right?)
In other words, each use of /foreach/ causes
foo() to keep its state information for each
client (right?)
What's more, /foreach/ does not seem to merely /call/
foo(), it does something else, because NOT using
/foreach/ but calling foo() explicitly resets
the counter for every call. Here is an example
for two generators/iterators. I want to pipe the
output of the number-generator into a generator
that packs them up into arrays of three numbers
each.
0 1 2 3 4 5 6 7 8 ... from NumberEnumerabl e
is fed into /ThreeNumbersEnu merable/ and
spits
{0 1 2} {3 4 5} {6 7 8} ...
Here is my naive implementation that does not
work:
namespace TestEnumeration
{
public class NumberEnumerabl e
{
// So far so good, spitting numbers
public IEnumerator<int > GetEnumerator()
{
int counter = 0;
for (; ; )
{
yield return counter++;
}
}
}
// The packer...
public class ThreeNumberEnum erable
{
int[] three = new int[3];
NumberEnumerabl e nen = new NumberEnumerabl e();
public IEnumerator<int[]> GetEnumerator()
{
for(;;)
{
for(int i = 0; i < 3; i++)
{
// Let's call GetEnumerator!
// Let's get numbers!
three[i] = nen.GetEnumerat or().Current;
nen.GetEnumerat or().MoveNext() ;
}
// Return the next 3-pack
yield return three;
}
}
}
class Program
{
static void Main(string[] args)
{
ThreeNumberEnum erable lb = new ThreeNumberEnum erable();
// DISAPPOINTMENT!
// We get packs of {0 0 0} -- the counter
// is reset each time
foreach (int[] i3 in lb)
{
Console.WriteLi ne("{0} {1} {2}", i3[0], i3[1], i3[2]);
}
}
}
}
All this means I can't CALL nen.GetEnumerat or(), I have
to do something else, but what? Am I supposed to do it
this way in first place?
Kind regards
Tin