Enumerando uma coleção, em seguida, modificá-lo, o que é o precedente para lançar uma exceção?
-
18-09-2019 - |
Pergunta
Quando enumerando uma coleção .NET, estados MSDN que:
Um enumerador permanece válido, desde que a coleção permanece inalterada. Se as mudanças são feitas para a recolha, tal como adicionar, modificar ou apagar elementos, o entrevistador é irrecuperavelmente invalidada e o seu comportamento é indefinido.
O que significa exatamente "irremediavelmente invalidado" significa?
Tome uma árvore binária, por exemplo, com referências tanto para baixo para crianças esquerda e direita, e também até pai. Em tal árvore uma, uma única referência a um único nó na árvore é suficiente para navegar através da árvore como você pode facilmente encontrar o próximo nó na árvore a partir dele.
Assim, com essa árvore, suponha que eu remover algum outro nó (presumivelmente, eu não remover o nó Atualmente estou sentado em), deve ainda invalidar o enumerador? Note que eu não estou falando de operação multi-threaded aqui, apenas um único segmento executando um loop, e modificar a coleção no interior do corpo do laço.
É este "direito" realmente, uma lei, que, mesmo se o enumerador poderia continuar, não deveria?
Solução
É este "direito" realmente, uma lei, que, mesmo se o enumerador poderia continuar, não deveria?
Pessoalmente, eu acho que ter o seu lance recenseador, mesmo que teoricamente poderia continuar, é uma boa prática.
Muitas vezes, as pessoas, inadvertidamente, colocar o código que muda um interior coleção de um loop foreach. Sem isso, não pode estar jogando no caso específico o desenvolvedor está atualmente testando, mas uma condição de tempo de execução diferente poderia facilmente fazê-lo jogar.
Por sempre jogando, você está forçando o desenvolvedor para tratar o seu código o mesmo como coleções e enumerações do quadro, que eu acho que é uma coisa boa, uma vez que reduz o nível de surpresa quando se lida com a sua biblioteca.
Outras dicas
A implementação dos recenseadores padrão da coleção faz com que seja uma lei. Quando eles são criados, ele copia um inteiro privado "versão" do objeto de coleção. Modificando a coleção incrementa essa versão. Os métodos de iterador comparar a versão e quando há uma incompatibilidade ele lança. Não há maneira de contornar isso.
No entanto, há uma classe de coleção que permite modificar a coleção, enquanto eles são enumerados: Microsoft.VisualBasic.Collection. É necessário fazê-lo para ficar compatível com a classe VB6 Collection. Você pode querer dar uma olhada para ver como ele é feito. IIRC, ele mantém um WeakReference em todos os iteradores, em seguida, atualizar os iteradores quando a coleção é modificado. Isto não é à prova de idiotas é claro, a remoção de um elemento e adicionando-o novamente pode enumerar o mesmo objeto duas vezes. Também não é barato.