Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manually increment an enumerator inside foreach loop

I have a nested while loop inside a foreach loop where I would like to advance the enumerator indefinitately while a certain condition is met. To do this I try casting the enumerator to IEnumerator< T > (which it must be if it is in a foreach loop) then calling MoveNext() on the casted object but it gives me an error saying I cannot convert it.

Cannot convert type 'System.DateTime' to System.Collections.Generic.IEnumerator via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion.

        foreach (DateTime time in times)
        {
            while (condition)
            {
                // perform action
                // move to next item
                (time as IEnumerator<DateTime>).MoveNext(); // will not let me do this
            }

            // code to execute after while condition is met
         }

What is the best way to manually increment the IEnumerator inside of the foreach loop?

EDIT: Edited to show there is code after the while loop that I would like executed once the condition is met which is why I wanted to manually increment inside the while then break out of it as opposed to continue which would put me back at the top. If this isn't possible I believe the best thing is to redesign how I am doing it.

like image 839
Despertar Avatar asked Feb 13 '12 01:02

Despertar


2 Answers

Many of the other answers recommend using continue, which may very well help you do what you need to do. However, in the interests of showing manually moving the enumerator, first you must have the enumerator, and that means writing your loop as a while.

using (var enumerator = times.GetEnumerator())
{
    DateTime time;
    while (enumerator.MoveNext()) 
    {
        time = enumerator.Current;
        // pre-condition code
        while (condition)
        {
            if (enumerator.MoveNext())
            {
                time = enumerator.Current;
                // condition code
            }
            else 
            {
                condition = false;
            }
        }
        // post-condition code
    }
}

From your comments:

How can the foreach loop advance it if it doesn't implement the IEnumerator interface?

In your loop, time is a DateTime. It is not the object that needs to implement an interface or pattern to work in the loop. times is a sequence of DateTime values, it is the one that must implement the enumerable pattern. This is generally fulfilled by implementing the IEnumerable<T> and IEnumerable interfaces, which simply require T GetEnumerator() and object GetEnumerator() methods. The methods return an object implementing IEnumerator<T> and IEnumerator, which define a bool MoveNext() method and a T or object Current property. But time cannot be cast to IEnumerator, because it is no such thing, and neither is the times sequence.

like image 149
Anthony Pegram Avatar answered Oct 15 '22 02:10

Anthony Pegram


You cannot modify the enumerator from inside the for loop. The language does not permit this. You need to use the continue statement in order to advance to the next iteration of a loop.

However, I'm not convinced that your loop even needs a continue. Read on.

In the context of your code you would need to convert the while to an if in order to make the continue refer to the foreach block.

foreach (DateTime time in times)       
{    
     if (condition) 
     {
             // perform action
             continue;
     }
     // code to execute if condition is not met    
}

But written like this it is clear that the following equivalent variant is simpler still

foreach (DateTime time in times)       
{    
     if (condition) 
     {
             // perform action
     }
     else
     {
            // code to execute if condition is not met   
     } 
}

This is equivalent to your pseudo-code because the part marked code to execute after while condition is met is executed for each item for which condition is false.

My assumption in all of this is that condition is evaluated for each item in the list.

like image 32
David Heffernan Avatar answered Oct 15 '22 01:10

David Heffernan