Подтвердить что ты не робот

Пройдя через сумасшедший, когда он может быть изменен?

Я хочу сделать цикл foreach, вынимая членов этого цикла foreach, но это бросает ошибки. Моя единственная идея - создать еще один список внутри этого цикла, чтобы найти, какие фрагменты удалить, и пропустить новый список, чтобы удалить элементы из Pizza.

foreach(var Slice in Pizza)
{
    if(Slice.Flavor == "Sausage")
    {
        Me.Eat(Slice); //This removes an item from the list: "Pizza"
    }
}
4b9b3361

Ответ 1

Вы можете сделать это, на самом деле самый простой способ, который я нашел (например, думать, что я его придумал, уверен, что не правда, хотя;))

foreach (var Slice in Pizza.ToArray())
{
    if (Slice.Flavor == "Sausage") // each to their own.. would have gone for BBQ
    {
        Me.Eat(Slice);
    }
}

.. потому что он итерирует по фиксированной копии цикла. Он будет перебирать все элементы, даже если они удалены.

Удобно, не так ли?

(Кстати, ребята, это удобный способ итерации через копию коллекции, с безопасностью потока и удаление времени блокировки объекта: Lock, получить копию ToArray(), отпустить блокировку, затем итерацию)

Надеюсь, что это поможет!

Ответ 2

Если вам нужно выполнить итерацию по списку и удалить элементы, повторите ее с помощью цикла for:

// taken from Preet Sangha answer and modified
for(int i = Pizza.Count-1; i >= 0, i--)
{
    var Slice = Pizza[i];
    if(Slice.Flavor == "Sausage")
    {
        Me.Eat(Slice); //This removes an item from the list: "Pizza"
    }
}

Причина повторения итерации заключается в том, что когда вы удаляете Elements, вы не запускаете исключение IndexOutOfRangeException, вызванное доступом к Pizza [5] на пицце, которая имеет только 5 элементов, потому что мы удалили шестой.

Причина использования цикла for заключается в том, что переменная i-итератора я не имеет отношения к Pizza, поэтому вы можете модифицировать пиццу без перерассеяния "break"

Ответ 3

используйте цикл for, а не foreach

for(int i = 0; i < in Pizza.Count(), ++i)
{

    var Slice = Pizza[i];
    if(Slice.Flavor == "Sausage")
    {
        Me.Eat(Slice); //This removes an item from the list: "Pizza"
    }
}

Ответ 4

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

List<Slice> slicesToEat=new List<Slice>();
foreach(var Slice in Pizza)
{
    if(Slice.Flavor == "Sausage")
    {
        slicesToEat.Add(Slice); 
    }
}
foreach(var slice in slicesToEat)
{
    Me.Eat(slice);
}

Ответ 5

Возможно, замените свою подпись Me.Eat() на IEnumerable<Slice>

Me.Eat(Pizza.Where(s=>s.Flavor=="Sausage").ToList());

Это позволяет выполнить задачу в 1 строке кода.

Тогда ваш Eat() может выглядеть следующим образом:

public void Eat(IEnumerable<Slice> remove)
{
    foreach (Slice r in remove)
    {
        Pizza.Remove(r);
    }
}

Ответ 6

Объект "Коллекция", созданный в стиле VB6, допускает модификацию во время перечисления и, похоже, работает разумно, когда происходят такие изменения. Слишком плохо, что у него есть другие ограничения (тип ключа ограничен строками без учета регистра) и не поддерживает generics, поскольку ни один из других типов коллекций не позволяет изменять.

Откровенно говоря, я не понимаю, почему контракт Microsoft iEnumerable требует, чтобы исключение было выбрано, если коллекция была изменена. Я бы понял, что исключение будет выбрано, если изменения в коллекции сделают невозможным продолжение перечисления без ошибок (пропуская или дублируя значения, которые не изменялись при перечислении, сбоях и т.д.), Но не видят причин, по которым разрешить сбор, который мог бы разумно перечислить это.

Ответ 7

Где вы можете заказать пиццу, где на срезах есть отдельные начинки? В любом случае...

Использование Linq:

// Was "Me.Eat()" supposed to be "this.Eat()"?
Pizza
    .Where(slice => slice.Flavor == "Sausage")
    .Foreach(sausageSlice => { Me.Eat(sausageSlice); });    

Первые две строки создают новый список только с обрезками колбасы. Третий возьмет это новое подмножество и передаст каждый фрагмент Me.Eat(). {И;} могут быть излишними. Это не самый эффективный метод, потому что он сначала делает копию (как и многие другие подходы, которые были даны), но она, безусловно, чистая и читаемая.

Кстати, это только для потомков, поскольку лучший ответ уже был задан - итерация назад по индексу.

Ответ 8

Какая коллекция - пицца? Если это List <T> то вы можете вызвать метод RemoveAll:

Pizza.RemoveAll(slice => string.Equals(slice.Flavor, "Sausage"));