Return to first element in foreach
Say I move开发者_如何学运维 with foreach loop in some collection.
At some point (e.g. by 4th elem) I want to return to first element of this collection (to go through all the elements again)
How to do this?
EDIT
Solution in comment by @dlev + enumerator.Reset()
Though this solution is inelegant, and plenty of people will tell you that it exposes you to all manner of danger, you can always just do:
Restart:
foreach(var item in things)
{
DoSomething(item);
if(WeShouldStartOver()) goto Restart;
}
That is easy, clear and correct. (A lot of people will reflexively tell you that gotos are the spawn of evil and always wrong. Those people might be confusing "inelegant" and "easily abused" with "morally wrong".)
If you're one of those people who thinks that gotos are always wrong, you can hide the goto. Mysteriously, when you spell "goto" as "while" and "break" it is no longer morally wrong!
bool loopTheLoop = true;
while(loopTheLoop)
{
loopTheLoop = false;
foreach(var item in things)
{
DoSomething(item);
if(WeShouldStartOver())
{
loopTheLoop = true;
break;
}
}
}
That is much longer, has way more complicated control flow, and uses a data flag just for control flow, rather than for expressing the meaning in the business domain of the program. I would argue that all of those things are as bad as the "goto", but some people really like this sort of thing.
I personally would be inclined to refactor the loop into a helper method:
while(LoopTheLoop()) {}
...
// Returns true if we bailed early, false if we did not.
bool LoopTheLoop()
{
foreach(var item in things)
{
DoSomething(item);
if(WeShouldStartOver()) return true;
}
return false;
}
Can you explain why you want to do this strange thing? Maybe there is a better way to do what you want. Because frankly, all these solutions are pretty bad.
Use a for loop instead. Or a while loop.
Don't think there is anything build in but how about...
bool tryAgian = false;
do
{
tryAgian = false;
foreach(var item in items)
{
//do something
if(needToStartAgain)
{
tryAgain = true;
break;
}
}
} while(tryAgain)
EDIT: Optimised
You can't really do that as far as I know.
Just use different loop, for example while
where you can control the iterator and decide if you increase or descrease it etc.
for(int i = 0;i<YourCollection.Count ; i++)
{
if(YouNeedToStartOver)
{
i=-1;
continue;
}
}
Within a foreach
you can only go to the next element with continue
or step out of the loop completely. You would need to use the iterator directly.
you could do something of this sort
private static void LoopMethod()
{
i= 0;
foreach (string str in jack)
{
if (i == 4)
LoopMethod();
Console.WriteLine(str);
i++;
}
}
I would consider creating and using an Enumerator of the collection if I were you.
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
while (enumerator.MoveNext())
{
if (SatisfyResetCondition(enumerator.Current))
enumerator.Reset();
Console.WriteLine(enumerator.Current);
}
}
You can't do this with a foreach loop over a collection, because when you use a foreach loop, you cannot get access to the Enumerator being used (it's hidden by the compiler - which is the whole point of the foreach loop!), and a collection does not necessarily have an indexer for direct access to the elements.
Even if you could, the interface contract for IEnumerator.Reset specifies that you do not have to implement Reset at all and can throw an exception instead. This means you cannot guarantee, for all collections, that Enumerator.Reset will return you to the beginning of the collection.
So no, you can't do what you have asked in the question; it is impossible.
精彩评论