Вы можете сделать так, это самый простой способ, который я нашел (хочется думать, что я его придумал, хотя это не так ;))
foreach (var Slice in Pizza.ToArray())
{
if (Slice.Flavor == "Sausage") // each to their own.. would have gone for BBQ
{
Me.Eat(Slice);
}
}
... потому что это итерация над фиксированной копией цикла. Он будет перебирать все элементы, даже если они удалены.
Удобно, не правда ли!
(Кстати, ребята, это удобный способ итерации по копии коллекции, с безопасностью потока и удалением времени блокировки объекта: Заблокировать, получить копию ToArray(), снять блокировку, затем выполнить итерацию)
Надеюсь, это поможет!
Если вам нужно выполнить итерацию по списку и нужно удалить элементы, повторите итерацию в обратном направлении с помощью цикла for:
// taken from Preet Sangha's 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"
}
}
Причина итерации в обратном направлении заключается в том, что при удалении элементов вы не сталкивайтесь с IndexOutOfRangeException, вызванным доступом к Pizza [5] в Pizza, которая имеет только 5 элементов, потому что мы удалили шестой.
Причина использования цикла for заключается в том, что переменная итератора i не имеет отношения к Pizza, поэтому вы можете изменить Pizza без "нарушения" перечислителя
Что это за коллекция Pizza? Если это List RemoveAll
:
Pizza.RemoveAll(slice => string.Equals(slice.Flavor, "Sausage"));
Вероятно, самый ясный способ приблизиться к этому - создать список кусочков, которые нужно съесть, а затем обработать его, избегая изменения исходного перечисления в цикле. Я никогда не был поклонником использования для этого индексированных циклов, так как это может быть подвержено ошибкам.
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);
}
Возможно, измените подпись Me.Eat()
на IEnumerable
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);
}
}
используйте цикл 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"
}
}
Где можно заказать пиццу, у которой кусочки имеют отдельную начинку ? В любом случае ...
Использование Linq:
// Was "Me.Eat()" supposed to be "this.Eat()"?
Pizza
.Where(slice => slice.Flavor == "Sausage")
.Foreach(sausageSlice => { Me.Eat(sausageSlice); });
Первые две строки создают новый список, содержащий только кусочки колбасы. Третий возьмет это новое подмножество и передаст каждый фрагмент в Me.Eat (). {И;} могут быть лишними. Это не самый эффективный метод, потому что он сначала создает копию (как и многие другие предложенные подходы), но он, безусловно, чистый и читаемый.
Кстати, это только для потомков, так как лучший ответ уже был дан - итерация в обратном направлении по индексу.
Объект «Коллекция» в стиле VB6 допускает модификацию во время перечисления и, кажется, работает разумно, когда такие модификации происходят. Жаль, что он имеет другие ограничения (тип ключа ограничен строками без учета регистра) и не поддерживает универсальные типы, поскольку ни один из других типов коллекций не допускает модификации.
Честно говоря, мне непонятно, почему контракт Microsoft iEnumerable требует, чтобы при изменении коллекции генерировалось исключение. Я бы понял требование о создании исключения, если изменения в коллекции сделают невозможным продолжение перечисления без дурацкости (пропуск или дублирование значений, которые не изменились во время перечисления, сбоя и т. Д.), Но я не вижу причин не делать этого. позволить коллекции, которая могла бы разумно перечислить, сделать это.