ReadOnlyCollection não é uma coleção imutável

Imagem de capa ReadOnlyCollection não é uma coleção imutável

ReadOnlyCollection não é uma coleção imutável

Nesta postagem do blog, descobrimos como podemos alterar um ReadOnlyCollection para ter mais ou menos entradas do que seu estado original. Readonly não significa que seja imutável. Também vamos verificar o ImmutableArray.

Readonly não significa imutável

O ReadOnlyCollection que temos desde o .NET Framework 2.0 é uma boa maneira de dizer "Aqui está uma coleção que você não pode alterar". Em termos de implementação, é apenas uma camada fina em cima de uma coleção, que proíbe operações como Adicionar, Remover ou Limpar. Mas isso não significa que os elementos subjacentes não possam mudar.

Um ReadOnlyCollection não é uma representação imutável, é basicamente apenas uma exibição de uma coleção ou lista. Dito isso, se a lista original mudar, o ReadOnlyCollection também mudará.

var numbers = new List<int> { 1, 2 }; 
var readOnlyNumbersViaExtension = numbers.AsReadOnly();
var readOnlyNumbers = new ReadOnlyCollection<int>(numbers);
Console.WriteLine($"List count: {numbers.Count}");
Console.WriteLine($"ReadOnlyCollection via extension count: {readOnlyNumbersViaExtension.Count}");
Console.WriteLine($"ReadOnlyCollection via new count: {readOnlyNumbers.Count}");

A saída é bastante óbvia aqui:

Contagem de lista: 2 ReadOnlyCollection via contagem de extensão: 2 ReadOnlyCollection via nova contagem: 2

Mas e se adicionarmos um novo elemento à nossa lista original, qual é agora a saída?

numbers.Add(3); 

Console.WriteLine($"List count: {numbers.Count}");
Console.WriteLine($"ReadOnlyCollection via extension count: {readOnlyNumbersViaExtension.Count}");
Console.WriteLine($"ReadOnlyCollection via new count: {readOnlyNumbers.Count}");

E a saída é:

Contagem de lista: 3 ReadOnlyCollection via contagem de extensão: 3 ReadOnlyCollection via nova contagem: 3

Como uma visualização de banco de dados, também nossa visualização somente leitura da nossa lista é atualizada. Isso é tudo ruim? Claro que não, porque isso também tem algumas vantagens. O mais importante é que a operação subjacente para criar um ReadOnlyCollection é super barata. Isso pode ser feito em tempo O(1), pois não há alocação envolvida em primeiro lugar.

Real Immutability

Se queremos ter imutabilidade real, temos que tomar diferentes tipos. Por exemplo: ImmutableArray. Se fizermos o mesmo exemplo acima, obteremos o que esperaríamos de um tipo imutável:

var numbers = new List<int> { 1, 2 };
var immutableArray = numbers.ToImmutableArray();

Console.WriteLine($"List count: {numbers.Count}"); Console.WriteLine($"ImmutableArray count: {immutableArray.Length}");

numbers.Add(3); 

Console.WriteLine($"List count: {numbers.Count}");
Console.WriteLine($"ImmutableArray count: {immutableArray.Length}");

Saída:

List count: 2
ImmutableArray count: 2 
List count: 3 
ImmutableArray count: 2

Podemos ver que o Comprimento permanece o mesmo. A desvantagem é óbvia: temos que copiar todo o array de nossa lista original para nosso array imutável que custa O(n). A propósito, o mesmo vale para um ImmutableList.

Conclusão

ReadOnlyCollection como mostrado não são imutáveis. Eles são apenas uma exibição somente leitura de uma lista. Você como consumidor não pode alterá-los, mas isso não significa que o criador/proprietário original da lista não possa. Se você realmente precisa do estado atual que não pode ser alterado, você deve usar o ImmutableArray ou ImmutableList. Mesmo grandes sites como este erram esse conceito:

"uma coleção imutável pode ser usada com menos cópias e não precisamos nos preocupar com sua modificação. Isso pode tornar os programas mais simples e fáceis de raciocinar."

Quanto mais você sabe.