Estou usando um loop for ou foreach (não importa) para percorrer todos os meus objetos quando eles precisam ser atualizados ou desenhados. No entanto, quando um objeto é morto, quero que ele seja removido da coleção novamente.
Eu faço isso adicionando o objeto a uma lista de objetos mortos e, quando tudo foi desenhado e atualizado, passo por tudo nessa lista, removendo também os objetos da lista da fonte original.
Existe um jeito melhor de fazer isso?
Respostas:
Primeiro de tudo: terminologia. Se você diz "lista de lixo", as pessoas pensam que você está falando sobre o coletor de lixo. Vamos chamá-lo de "lista morta".
Como você provavelmente descobriu, daí a sua pergunta, você não pode remover itens de uma coleção enquanto estiver iterando por ela. Se sua coleção é uma
List<>
maneira mais simples de remover itens, é:Observe que você itera para trás . Você pode remover itens enquanto faz a iteração para a frente, mas é mais confuso e requer um
goto
. Você não pode fazer isso comforeach
.Você pode fazer a remoção separadamente do seu loop de atualização. Ou você pode mesclá-lo ao seu loop de atualização. Sempre faça o
RemoveAt
final do loop - depois desse ponto no loop,list[i]
não poderá ser considerado válido (ele se tornará válido novamente na próxima iteração).Observe também que cada objeto tem seu próprio
IsDead
sinalizador (se você estiver usando o padrão de descarte, poderá fazê-loIsDisposed
) - você realmente não precisa manter uma "lista de mortos".É preferível o desempenho de um sinalizador em cada item, pois você evita procurar na lista para fazer a remoção. E também é preferível para o design - significa que cada objeto pode verificar facilmente se está morto - para que você não invoque acidentalmente nenhum método (se esses objetos estiverem implementando o padrão descartável, eles podem ser lançados
ObjectDisposedException
nesse caso).Se você tiver uma coleção diferente de uma
List<>
, a remoção de itens inativos dessa coleção ainda poderá envolver a criação de uma lista inoperante (pois a remoção durante a iteração pode não ser possível). Na minha opinião, é melhor, em termos de design, criar a lista de mortos imediatamente antes de ser usada, percorrendo a coleção procurandoIsDead
sinalizadores, em vez de tentar manter a lista à medida que os objetos são mortos.Depois de terminar com uma lista de mortos, você deve
Clear()
fazê - lo e mantê-lo por perto para reutilizá-lo mais tarde.fonte
IsDead
padrão é funcionalmente idêntico aIsDisposed
. O uso semânticoIsDead
implica que você esteja mantendo uma lista Draw / Update desses objetos que terão itens mortos removidos posteriormente. O padrão de descarte não implica isso. Além disso, o padrão de disposição não implica que você pode ter recursos não gerenciados detidas por esse objeto (o que geralmente não é apropriado para objectos de jogo).Em 99,9% do tempo, o coletor de lixo (GC) cuidará de tudo sem aborrecimentos. Apenas deixe-o fazer o seu trabalho depois de excluir / anular esses objetos. Há uma latência na limpeza que depende de vários fatores (quantos blocos de memória foram atribuídos, por exemplo), mas você normalmente não precisa nem saber disso, muito menos se preocupar com isso. Ele foi projetado para funcionar. Qual é o motivo pelo qual você está usando C # e não C.
Em relação ao desempenho do GC em geral, não se preocupe demais, a menos que você saiba (por meio de criação de perfil) que isso está criando um gargalo - isso é apenas em jogos bastante exigentes, em geral. Se for esse o caso, consulte GC.Collect () e suas várias armadilhas, para saber quando é apropriado usá-lo. Eu sugiro pesquisar no Google "force gc xna", há muito material por aí.
fonte