views:

113

answers:

2

I have some code i'd like to refactor that uses a C# iterator (ie IEnumerable). Unfortunately, I can't see to quite figure out the best way to allow other functions to work with the iterator without causing it to restart the iterator.

For example:

NewLineEnumerator nle = new NewLineEnumerator();

while (bytesRead > 0)
{
  var nlenum = nle.Process(inputData, bytesRead);
  foreach (string block in nlenum)
  {
    DoSomething(nlenum);
  }
}

void DoSomething(IEnumerable<string> myiter)
{
  foreach (var s in myiter)
  {
     // myiter is restarted, and begins at the start of the iterator again
  }
}

You might be asking why i would want to do this. The reason is that I have a stream of data, surrounded by "command blocks". Depending on the command, I send it to a different subfunction to process. So I want to keep iterating where i left off in the stream either at the start, or at the end.

Any suggestions here?

+5  A: 

Pass an IEnumerator<string> rather than the IEnumerable<string>, by calling GetEnumerator(). It will retain the state across calls.

Nick Gunn
However, you can't use an IEnumerator in a foreach
Mystere Man
No, but you could build a generic enumerable from one and pass that.
Nick Gunn
Can you elaborate?
Mystere Man
+2  A: 

As Nick said, create one IEnumerator<string> and pass it between methods. The code would look something like:

NewLineEnumerator nle = new NewLineEnumerator();

while (bytesRead > 0)
{
    var nlenum = nle.Process(inputData, bytesRead);
    using (var enumerator = nlenum.GetEnumerator())
    {
     while (enumerator.MoveNext())
     {
      DoSomething(enumerator);
      Console.WriteLine(enumerator.Current);
     }
    }

    // ensure that bytesRead is decremented by the code that runs above
}

void DoSomething(IEnumerator<string> myenum)
{
    while (myenum.MoveNext())
    {
        if (ShouldProcess(myenum.Current))
        {
            // process it
        }
        else
        {
            // return to outer loop
            break;
        }
    }
}

(Note that if you're using .NET 1.0, and IEnumerable, not IEnumerable<string>, the using statement may not compile.)

Bradley Grainger