ADN Open CIS
Сообщество программистов Autodesk в СНГ

12/04/2015

Не добавляйте и не удаляйте элементы при перечислении коллекций элементов

Пользователь столкнулся с проблемой, что при загрузке семейства через API, Revit закрывается.

Вот его код:

Код - C#: [Выделить]
  1. UIApplication rvtApp = commandData.Application;
  2. UIDocument rvtDoc = rvtApp.ActiveUIDocument;
  3.  
  4. FilteredElementCollector collector =
  5.     new FilteredElementCollector(rvtDoc.Document)
  6.     .OfClass(typeof(Family));
  7. FilteredElementIterator itr =
  8.     collector.GetElementIterator();
  9. while (itr.MoveNext())
  10. {
  11.     Element elem = (Element)itr.Current;
  12.     ReloadFamily(rvtApp, rvtDoc, elem);
  13. }

Сначала выбираются все семейства, затем ищется соответствующий .rfa файл. Если он найден, то вызывается загрузка этого семейства с помощью метода Document.LoadFamily.

Мне удалось воспроизвести проблему, и я попытался выяснить в чем же причина.

Для начала я получил идентификаторы семейств, перед тем как вызывать метод ReloadFamily.

Код - C#: [Выделить]
  1. while (itr.MoveNext())
  2. {
  3.     Element elem = (Element)itr.Current;
  4.     WriteLog(elem.Id + ":" + elem.Name);
  5.     ReloadFamily(rvtApp, rvtDoc, elem);
  6. }

Посмотрев на результат, я обнаружил, что некоторые идентификаторы повторяются и в этом случае Revit падает.

Т.е. причина похоже именно в дубликатах.

Но, я ошибался.

Я попробовал изменить Iterator на foreach:

Код - C#: [Выделить]
  1. foreach (var elem in collector.ToElements())
  2. {
  3.     ReloadFamily(rvtApp, rvtDoc, elem);
  4. }

И… Revit больше не падает.

Вероятно, вы поняли, что причина не в foreach, а в методе ToElements(), который фактически создает новую коллекцию.

Таким образом, причина очевидна. Пока мы перечисляем элементы коллекции, мы сделали изменения в проекте, а именно, добавили новые элементы, что и вызвало падение Revit.

Давайте посмотри простой пример с коллекциями:

Код - C#: [Выделить]
  1. List<int> ids = new List<int>() { 1, 2, 3, 4 };
  2. foreach (int id in ids)
  3. {
  4.     ids.Add(5); //Исключение!!!
  5. }

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

Тоже самое происходит и с документом Revit, когда мы перечисляем элементы из проекта.

Итог: Не добавляйте и не удаляйте элементы при перечислении элементов проекта, за исключением случаев, когда вы перечисляете копию этой коллекции.

Источник: http://adndevblog.typepad.com/aec/2015/03/revitapido-not-add-or-delete-elements-when-iterating-document.html

Обсуждение: http://adn-cis.org/forum/index.php?topic=2629

Опубликовано 12.04.2015