Я использую цикл for или цикл foreach (не имеет значения), чтобы перебрать все мои объекты, когда их нужно обновить или нарисовать. Однако, когда объект убивают, я хочу, чтобы он снова был удален из коллекции.
Я делаю это, добавляя объект в список мертвых объектов, а затем, когда все прорисовано и обновлено, я просматриваю все в этом списке, удаляя также объекты в списке из исходного источника.
Есть ли лучший способ сделать это?
Ответы:
Прежде всего: терминология. Если вы скажете «список мусора», люди подумают, что вы говорите о сборщике мусора. Давайте назовем это «мертвым списком».
Как вы, вероятно, обнаружили, отсюда и ваш вопрос: вы не можете удалять элементы из коллекции, пока выполняете ее. Если ваша коллекция -
List<>
то самый простой способ удалить элементы из нее:Обратите внимание, что вы повторяете в обратном направлении . Вы можете удалять элементы во время итерации вперед, но это сложнее и требует
goto
. Вы не можете сделать это сforeach
.Вы можете сделать удаление отдельно от цикла обновления. Или вы можете объединить его в свой цикл обновления. Всегда делайте
RemoveAt
в конце цикла - после этой точки в цикле,list[i]
нельзя считать действительным (оно снова становится действительным на следующей итерации).Также обратите внимание, что каждый объект имеет свой собственный
IsDead
флаг (если вы используете шаблон удаления, вы можете сделать егоIsDisposed
) - вам вообще не нужно поддерживать «мертвый список».Использование флага для каждого элемента предпочтительнее для производительности, так как вам не нужно искать в списке, чтобы выполнить удаление. И это также предпочтительно для дизайна - это означает, что каждый объект может легко проверить, мертв ли он, - так что вы случайно не вызываете какие-либо методы для него (если эти объекты реализуют одноразовый шаблон, они могут бросить
ObjectDisposedException
в этом случае).Если у вас есть коллекция, отличная от a
List<>
, то удаление мертвых элементов из этой коллекции может по-прежнему включать создание мертвого списка (поскольку удаление во время итерации может быть невозможным). На мой взгляд, лучше создавать дизайн мертвого списка непосредственно перед его использованием, перебирая коллекцию в поискахIsDead
флагов, вместо того, чтобы пытаться поддерживать список при уничтожении объектов.Как только вы закончили с мертвым списком, вы должны
Clear()
это сделать, а затем сохранить его для повторного использования позже.источник
IsDead
Картина функционально идентичныIsDisposed
. Семантическое использованиеIsDead
подразумевает, что вы ведете список Draw / Update этих объектов, из которого будут удалены мертвые элементы в будущем. Схема утилизации не подразумевает этого. Кроме того, схема утилизации действительно означает , что вы можете иметь неуправляемые ресурсы , принадлежащие этот объект (который, как правило , не подходит для объектов игрового процесса).В 99,9% случаев сборщик мусора (GC) позаботится обо всем без проблем. Просто дайте ему сделать свою работу, как только вы удалите / обнуляете эти объекты. Существует задержка в очистке, которая зависит от ряда факторов (например, сколько блоков памяти было выделено), но вам обычно не нужно даже знать об этом, не говоря уже о том, чтобы беспокоиться об этом. Он предназначен только для работы. По какой причине вы используете C #, а не C.
Относительно производительности GC в целом, не беспокойтесь слишком сильно, если только вы не знаете (через профилирование), что это создает узкое место - это только в довольно требовательных играх, как правило. Если это так, посмотрите на GC.Collect () и его различные подводные камни, чтобы вы знали, когда это целесообразно использовать. Я предлагаю погуглить "force gc xna", там много материала.
источник