Вернуться к первому элементу в foreach - PullRequest
2 голосов
/ 20 июля 2011

Скажем, я перехожу с циклом foreach в некоторой коллекции.

В какой-то момент (например, к 4-му элементу) я хочу вернуться к первому элементу этой коллекции (чтобы снова просмотреть все элементы)

Как это сделать?

РЕДАКТИРОВАТЬ

Решение в комментарии @dlev + enumerator.Reset ()

Ответы [ 9 ]

15 голосов
/ 20 июля 2011

Хотя это решение не элегантно, и многие люди скажут вам, что оно подвергает вас всевозможным опасностям, вы всегда можете просто сделать:

Restart:
foreach(var item in things)
{
    DoSomething(item);
    if(WeShouldStartOver()) goto Restart;
}

Это легко, понятно и правильно. (Многие люди рефлексивно скажут вам, что gotos являются порождением зла и всегда неправы. Эти люди могут путать «неэгоистичную» и «легко злоупотребляемую» с «морально неправильной».)

Если вы один из тех людей, которые думают, что goto всегда неправы, вы можете скрыть goto. Таинственным образом, когда вы произносите «goto» как «while» и «break», это больше не является морально неправильным!

bool loopTheLoop = true;
while(loopTheLoop)
{
    loopTheLoop = false;
    foreach(var item in things)
    {
        DoSomething(item);
        if(WeShouldStartOver())
        {
            loopTheLoop = true;
            break;
        }
    }
}

Это намного дольше, имеет гораздо более сложный поток управления и использует флаг данных только для потока управления, а не для выражения значения в бизнес-сфере программы. Я бы сказал, что все эти вещи такие же плохие, как «goto», но некоторым людям действительно нравятся такие вещи.

Лично я был бы склонен преобразовать цикл в вспомогательный метод:

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;
}

Можете ли вы объяснить почему вы хотите сделать эту странную вещь? Может быть, есть лучший способ сделать то, что вы хотите. Потому что, честно говоря, все эти решения довольно плохие.

10 голосов
/ 20 июля 2011

Вместо этого используйте цикл for. Или цикл пока.

5 голосов
/ 20 июля 2011

Не думаю, что есть что-то встроенное, но как насчет ...

bool tryAgian = false;
do
{
   tryAgian = false;
   foreach(var item in items)
   {
      //do something
      if(needToStartAgain)
      {
         tryAgain = true;
         break;
      }
   }
} while(tryAgain)

РЕДАКТИРОВАТЬ: оптимизировано

1 голос
/ 20 июля 2011
for(int i = 0;i<YourCollection.Count ; i++)
{
    if(YouNeedToStartOver)
    {
        i=-1;
        continue;
    }
}
1 голос
/ 20 июля 2011

Насколько я знаю, ты не можешь этого сделать.

Просто используйте другой цикл, например while, где вы можете управлять итератором и решать, увеличивать или уменьшать его и т. Д.

0 голосов
/ 20 июля 2011

Вы не можете сделать это с помощью цикла foreach над коллекцией, потому что когда вы используете цикл foreach, вы не можете получить доступ к используемому Enumerator (он скрыт компилятором - в этом и заключается весь смысл цикла foreach). !), а коллекция не обязательно имеет индексатор для прямого доступа к элементам.

Даже если бы вы могли, интерфейсный контракт для IEnumerator.Reset указывает, что вам вообще не нужно реализовывать Reset, и вместо этого вы можете вызвать исключение. Это означает, что вы не можете гарантировать для всех коллекций, что Enumerator.Reset вернет вас в начало коллекции.

Так что нет, вы не можете делать то, что спросили в вопросе; это невозможно.

0 голосов
/ 20 июля 2011

Я бы подумал о создании и использовании перечислителя коллекции на вашем месте.

    using (IEnumerator<T> enumerator = collection.GetEnumerator())
    {

        while (enumerator.MoveNext())
        {
            if (SatisfyResetCondition(enumerator.Current))                          
                enumerator.Reset();
            Console.WriteLine(enumerator.Current);
        }
    }
0 голосов
/ 20 июля 2011

вы могли бы сделать что-то в этом роде

   private static void LoopMethod()
        {
           i= 0;
            foreach (string str in jack)
            {
                if (i == 4)
                    LoopMethod();

                Console.WriteLine(str);
                i++;
            }
        }
0 голосов
/ 20 июля 2011

В пределах foreach вы можете перейти только к следующему элементу с continue или полностью выйти из цикла.Вам нужно будет использовать итератор напрямую.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...