J'utilise une boucle for ou une boucle foreach (peu importe) pour parcourir tous mes objets lorsqu'ils doivent être mis à jour ou dessinés. Cependant, lorsqu'un objet est tué, je veux qu'il soit à nouveau supprimé de la collection.
Je fais cela en ajoutant l'objet à une liste d'objets morts, puis, lorsque tout a été dessiné et mis à jour, je passe en revue tout ce qui se trouve dans cette liste, en supprimant également les objets de la liste de la source d'origine.
Existe-t-il une meilleure façon de le faire?
Réponses:
Tout d'abord: la terminologie. Si vous dites "liste des ordures", les gens penseront que vous parlez du ramasse-miettes. Appelons cela la "liste morte".
Comme vous l'avez probablement découvert, d'où votre question, vous ne pouvez pas supprimer des éléments d'une collection pendant que vous parcourez celle-ci. Si votre collection est une,
List<>
la façon la plus simple de supprimer des éléments est:Notez que vous répétez en arrière . Vous pouvez supprimer des éléments tout en itérant vers l'avant, mais c'est plus compliqué et nécessite un
goto
. Vous ne pouvez pas le faire avecforeach
.Vous pouvez soit effectuer la suppression séparément de votre boucle de mise à jour. Ou vous pouvez le fusionner dans votre boucle de mise à jour. Faites toujours le
RemoveAt
à la fin de la boucle - après ce point de la boucle,list[i]
ne peut pas être considéré comme valide (il redevient valide à la prochaine itération).Notez également que chaque objet a son propre
IsDead
indicateur (si vous utilisez le modèle d'élimination, vous pouvez le créerIsDisposed
) - vous n'avez pas du tout besoin de maintenir une "liste morte".L'utilisation d'un indicateur sur chaque élément est préférable pour les performances, car vous évitez d'avoir à parcourir la liste pour effectuer la suppression. Et il est également préférable pour la conception - cela signifie que chaque objet peut facilement vérifier s'il est mort - afin de ne pas appeler accidentellement de méthodes dessus (si ces objets implémentent le modèle jetable, ils pourraient le lancer
ObjectDisposedException
dans ce cas).Si vous avez une collection autre que a
List<>
, la suppression des éléments morts de cette collection peut toujours impliquer la création d'une liste morte (car la suppression pendant l'itération peut ne pas être possible). À mon avis, il est plus agréable, au niveau de la conception, de créer la liste morte juste avant qu'elle ne soit utilisée, en parcourant la collection à la recherche deIsDead
drapeaux, plutôt qu'en essayant de maintenir la liste lorsque des objets sont tués.Une fois que vous avez terminé avec une liste morte, vous devez la
Clear()
conserver, puis la conserver pour la réutiliser plus tard.la source
IsDead
motif est fonctionnellement identique àIsDisposed
. L'utilisation sémantiqueIsDead
implique que vous maintenez une liste de tirage / mise à jour de ces objets dont les éléments morts seront supprimés ultérieurement. Le modèle d'élimination n'implique pas cela. De plus, le modèle d'élimination n'implique que vous pouvez disposer de ressources non gérés détenues par cet objet (qui est généralement pas approprié pour les objets de gameplay).99,9% du temps, le ramasse-miettes (GC) s'occupe de tout sans tracas. Laissez-le faire son travail une fois que vous avez supprimé / annulé ces objets. Il y a une latence dans le nettoyage qui dépend d'un certain nombre de facteurs (combien de blocs de mémoire ont été affectés par exemple) mais vous n'avez généralement pas besoin de le savoir, et encore moins de vous en soucier. Il est conçu pour fonctionner. C'est une des raisons pour lesquelles vous utilisez C # et non C.
Concernant les performances du GC en général, ne vous inquiétez pas trop à moins que vous ne sachiez (par profilage) que cela crée un goulot d'étranglement - ce n'est que dans les jeux assez exigeants, en général. Si tel est le cas, examinez GC.Collect (), et ses divers pièges, afin de savoir quand il convient de l'utiliser. Je suggère de googler "force gc xna", il y a beaucoup de matériel là-bas.
la source