2009-09-15 2 views
1

Это ситуация:Foreach при добавлении элементов в обхвате коллекции

Я просматривал какой-то код, и я подумал, если следующий оператор принимает ссылку выбранной коллекции или копию, с которой он заменяет оригинал объект, когда контур foreach завершается. Если первое, возьмут ли новые найденные страницы и присоединятся к ним в цикле?

foreach(Page page in Pages) 
{ 
    page.AddRange(RetrieveSubPages(page.Id)); 
} 

Редактировать: Извините, я сделал опечатку.

Это должно быть так:

foreach(Page page in pages) 
{ 
    pages.AddRange(RetrieveSubPages(page.Id)); 
} 

Что я пытался сказать, что если я добавить некоторые объекты в коллекции Enumerating, будет ли он присоединиться к этим объектам в Еогеасп?

ответ

1

В ответ на вопрос, он не делает копию.

Он создает перечислитель и выполняет итерацию через коллекцию.Если коллекция изменяется в то время как это перечисление происходит, в самом Еогеасп, или асинхронно, вы получите исключение:

Необработанное исключение типа «System.InvalidOperationException» произошло в mscorlib.dll

Дополнительная информация : Коллекция была изменена; операция перечисления может не выполняться.

Вы можете использовать временную коллекцию и присоединиться к ней после или просто не использовать перечислитель.

for (int i = 0; i < pages.Count; i++) 
    { 
     test.AddRange(RetrieveSubPages(pages[i].Id)); 
    } 
1

foreach использует перечислитель. Коллекция, в которой вы используете цикл foreach, должна реализовать IEnumerable (или IEnumerable<T>). Затем foreach вызывает метод GetEnumerator этой коллекции и использует Enumerator для перемещения коллекции.

4

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

5

Похоже, что код не изменяет коллекцию Pages, а содержимое объектов в объектах Page в коллекции Pages. Тип Page имеет, по меньшей мере, подобный метод сбора.

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

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

0

Я уверен, что вы получите исключение брошенного жалуясь, что лежащая в основе коллекция была модифицирован

1

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

Также не имеет значения, если клоун коллекции перечислили, поскольку объекты, содержащиеся как в коллекции, так и в клоне, по-прежнему остаются одинаковыми (ссылочные равны).

2

Я думаю, что самый безопасный способ заключается в следующем:

Array<Page> newpages = new Array<Page>();  
foreach(Page page in pages) 
{ 
    newpages.AddRange(RetrieveSubPages(page.Id)); 
} 

pages.AddRange(newpages); 

Вы должны были бы продлить этот бит, если вы хотите рекурсию в подстраниц.

Смежные вопросы