Изменение коллекции при использовании цикла foreach в c# [дубликат]
этот вопрос уже есть ответ здесь:
В основном, я хотел бы удалить элемент из списка, находясь внутри цикла foreach. Я знаю, что это возможно при использовании цикла for, но для других целей, я хотел бы знать, если это это достижимо с помощью цикла foreach.
в python мы можем достичь этого, выполнив следующее:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for i in a:
print i
if i == 1:
a.pop(1)
Это дает следующий результат
>>>1
3
4
5
6
7
8
9
но когда я делаю что-то подобное в c#, я получаю исключение InvalidOperationException, мне было интересно, есть ли способ обойти это,без Просто использования цикла for.
код в C#, который я использовал, когда было создано исключение:
static void Main(string[] args)
{
List<string> MyList = new List<string>(new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9"});
foreach (string Item in MyList)
{
if (MyList.IndexOf(Item) == 0)
{
MyList.RemoveAt(1);
}
Console.WriteLine(Item);
}
}
спасибо заранее
3 ответов
вы не можете этого сделать. Из документов для IEnumerator<T>
:
перечислитель остается действительным до тех пор, пока коллекция остается неизменной. Если изменения вносятся в коллекцию, например, добавление, изменение или удаление элементов, перечислитель становится безвозвратно признана недействительной и ее поведение не определено.
варианты:
- создайте новый список элементов для удаления, а затем удалите их все потом! .. --16-->
- используйте обычный цикл" для " и убедитесь, что вы осторожны, не переходя через один и тот же элемент дважды или не хватает. (Вы сказали, что не хотите этого делать, но то, что вы пытаетесь сделать, просто не сработает.)
- создайте новую коллекцию, содержащую только элементы, которые вы хотите сохранить
последней из этих альтернатив является LINQ-подобное решение, где вы обычно пишете:
var newList = oldList.Where(x => ShouldBeRetained(x)).ToList();
(где ShouldBeRetained
- это все логика ты, конечно, хочешь.) Вызов ToList()
необходимо только если вы действительно хотите, чтобы он был в списке. Это приводит к более декларативному коду, который часто легче читать. Я не могу легко догадаться, что должен делать ваш исходный цикл (на данный момент это кажется довольно странным), тогда как если вы можете выразить логику исключительно в терминах элемента, это может быть намного яснее.
Если все, что вам нужно, это удалить все элементы, которые удовлетворяют условию, вы можете использовать Список
List<string> MyList = new List<string>(new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9" });
MyList.RemoveAll(item => item == "1");
обратите внимание, что это изменяет первоначальный список.
вы определенно не можете изменить коллекцию каким-либо образом при использовании цикла foreach на нем.
вы можете использовать цикл for и управлять индексом для себя или сделать копию коллекции и, как вы цикл оригинала, удалить элементы из копии, которые равны элементу в оригинале.
в обоих случаях это не совсем так, как понятно и удобно :).