Pergunta

Imagine que durante uma

foreach(var item in enumerable)

O itens enumeráveis ??mudança. Vai afetar o foreach atual?

Exemplo:

var enumerable = new List<int>();
enumerable.Add(1);
Parallel.ForEach<int>(enumerable, item =>
{ 
     enumerable.Add(item + 1);
});

Ele fará um loop para sempre?

Foi útil?

Solução

Geralmente, ele deve lançar uma exceção. A implementação List<T> de GetEnumerator () Fornece um objeto Enumerator<T> cuja MoveNext() método se parece com isso (a partir do refletor):

public bool MoveNext()
{
    List<T> list = this.list;
    if ((this.version == list._version) && (this.index < list._size))
    {
        this.current = list._items[this.index];
        this.index++;
        return true;
    }
    return this.MoveNextRare();
}


private bool MoveNextRare()
{
    if (this.version != this.list._version)
    {
        ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
    }
    this.index = this.list._size + 1;
    this.current = default(T);
    return false;
}

O list._version é modificado (incrementado) em cada operação que modifica a lista.

Outras dicas

Depende da natureza do recenseador. Muitos deles jogar exceção quando as mudanças de cobrança.

Por exemplo, List<T> lança uma InvalidOperationException se a coleção muda durante a enumeração.

Isso depende totalmente de como IEnumerable é implementado.

Com uma lista, ele irá lançar uma IllegalOperationException. Mas não contar com esse comportamento para IEnumarables. Alguns loop infinito e irá lançar um OutOfMemoryException rapidamente.

documentação da Microsoft para IEnumerable [e IEnumerable<T> - nomes não-genéricos nos referir a ambos] recomenda que a qualquer momento um objeto implementar essas interfaces for alterado, ele deve invalidar quaisquer instâncias de IEnumerator [IEnumerator<T>] que produziu anteriormente, causando -los para jogar InvalidOperationException em futuras tentativas de acesso. Embora nada na documentação do Microsoft documentou qualquer alteração a partir desta posição, suas implementações reais de IEnumerable parecem seguir uma regra mais flexível, o que é que um IEnumerator não deve comportar-se sem sentido se a coleção subjacente é modificada; ele deve jogar InvalidOperationException se ele não pode se comportar "sensata" . Infelizmente, uma vez que a regra não é explicitamente indicado, mas sim inferida a partir do comportamento de suas classes, não é claro o comportamento exatamente "sensível" deve significar.

Todas as classes Microsoft que eu sei de vontade irá lançar uma exceção quando uma coleção é alterada se eles não podem seguir os seguintes critérios:

  1. Qualquer item que existe sem modificações em toda a enumeração será devolvido exatamente uma vez.
  2. Um produto que é adicionado ou suprimido durante a enumeração devem ser devolvidos com mais uma vez, mas, se um objecto é removido e re-adicionado durante a enumeração, cada re-adição pode ser considerado como a criação de um novo "produto" .
  3. Se um conjunto de garantias para retornar coisas em uma seqüência ordenada, essa garantia deve ser cumprida mesmo que são inseridos itens e removido [por exemplo, se um "Fred" é adicionado a uma lista em ordem alfabética-ordenadas, e "George" já foi enumerado, "Fred" não deve aparecer durante essa enumeração].

Seria útil se houvesse algum meio através do qual coleções poderia relatar se eles podem satisfazer os critérios acima (sem jogar exceções) mesmo quando modificado, uma vez que pode ser muito útil quando se tenta por exemplo remover todos os itens que atendem a um determinado critério.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top