Pergunta

Eu tenho um ICollection<T> chamado foos na minha classe que eu quero expor como somente leitura (ver esta questão ). Eu vejo que a interface define um .IsReadOnly propriedade, que parece apropriado ... A minha pergunta é esta: como faço para torná-lo óbvio para o consumidor da classe que foos é somente leitura?

Eu não quero contar com eles lembrar-se de .IsReadOnly consulta antes de tentar um método não-implementadas, como .Add(). Idealmente, eu gostaria de expor foos como um ReadOnlyCollection<T>, mas não implementa IList<T>. Devo expor foo através de um método chamado, por exemplo, GetReadOnlyFooCollection em vez de através de uma propriedade? Em caso afirmativo, isso não confundir alguém que, em seguida, espera um ReadOnlyCollection<T>?

Esta é C # 2.0, assim como métodos de extensão ToList() não estão disponíveis ...

Foi útil?

Solução

I parecem ter resolvido em retornar IEnumerable com os objetos clonados.

public IEnumerable<Foose> GetFooseList() {
   foreach(var foos in Collection) {
     yield return foos.Clone();
   }
}
  • requer um método Clone em Foos.

Isso permite que qualquer alteração na coleção. Lembre-se que ReadOnlyCollection é "furado", já que os objetos dentro dele pode ser mudado como mencionado em um link no outro post.

Outras dicas

Você pode fazer "foos" um ReadOnlyCollection assim:

ReadOnlyCollection<T> readOnlyCollection = foos.ToList<T>().AsReadOnly();

Então você pode expô-la como uma propriedade de sua classe.

EDIT:

    class FooContainer
    {
        private ICollection<Foo> foos;
        public ReadOnlyCollection<Foo> ReadOnlyFoos { get { return foos.ToList<Foo>().AsReadOnly();} }

    }

Nota: Você deve se lembrar que uma vez que você começa a coleção ReadOnlyFoos não é mais "sincronizado" com seu ICollection foos. Veja a enfiar você referenciou .

Uma vez que a questão foi escrito, .NET 4.0 adicionou uma interface IReadOnlyCollection<T>; provavelmente seria bom para usar isso como o tipo de retorno declarado.

Isso, no entanto, deixar em aberto a questão de que tipo de exemplo para retornar. Uma abordagem seria para clonar todos os itens da coleção original. Outra seria para retornar sempre um read-only wrapper. Um terceiro seria para retornar a coleção original, se ele implementa IReadOnlyCollection<T>. Cada abordagem será a melhor em certos contextos, mas será menos do que o ideal (ou talvez absolutamente terrível) em outros. Infelizmente, a Microsoft não fornece meios padrão por que a pergunta pode ser feita duas questões muito importantes:

  1. Você promete para sempre e para sempre contêm os mesmos itens como você fazer agora?

  2. Você pode seguramente ser exposta diretamente ao código que não é suposto para modificar seu conteúdo.

Qual o estilo de embalagem é apropriado dependerá do que o código do cliente está esperando a ver com a coisa que recebe. Alguns cenários a serem evitadas:

  1. Um objeto foi fornecido de um tipo que o cliente iria reconhecer como imutável, mas em vez de ser devolvidos diretamente é duplicado, usando um tipo que o cliente não reconhece como imutável. Consequentemente, o cliente é obrigado a duplicar a coleção novamente.

  2. Um objeto foi fornecido de um tipo que o cliente iria reconhecer como imutável, mas antes de ser devolvido é envolto em tal forma que o cliente não pode dizer se a coleção é imutável ou não, e, portanto, é obrigado a duplicar.

  3. Um objeto do tipo mutável que não é suposto ser mutado é fornecido por um cliente (fundido a uma interface somente leitura). Em seguida, é exposta diretamente para outro cliente que determina que é um tipo mutável e prossegue para modificá-lo.

  4. A referência a uma coleção mutável é recebido e é encapsulado em um read-only invólucro antes de ser devolvida a um cliente que precisa de um objeto imutável. O método que voltou a coleção prometeu que é imutável, e, portanto, o cliente se recusou a fazer a sua própria cópia defensiva. O cliente é então mal preparados para a possibilidade de que a coleção pode mudar.

Não há realmente qualquer particularmente claro "seguro" de ação de um objeto pode levar com coleções que ele recebe de alguns clientes e necessidades para expor aos outros. Sempre duplicar tudo é em muitas circunstâncias o curso de ação mais seguro, mas pode facilmente resultar em situações em que uma coleção que não precisa ser repetido em todos acaba recebendo centenas duplicadas ou milhares de vezes. Retornando referências como recebeu muitas vezes pode ser a abordagem mais eficiente, mas também pode ser semanticamente perigoso.

Desejo Microsoft acrescentaria um meio padrão pelo qual coleções poderiam ser feitas as perguntas acima, ou, ainda melhor, ser convidado para produzir um instantâneo imutável de seu estado atual. Uma coleção imutável poderia retornar uma imagem imutável de seu estado atual muito mais barato (apenas em si retorno) e até mesmo alguns tipos de coleção mutáveis ??poderia retornar uma imagem imutável a um custo muito inferior ao custo de uma enumeração completa (por exemplo, um List<T> pode ser apoiado por dois matrizes T[][], uma das quais contém referências para matrizes imutáveis ??compartilháveis ??de 256 itens, e o outro de que mantém referências a matrizes mutáveis ??compartilhaveis de 256 itens. Fazer um instantâneo de uma lista exigiria clonagem única as séries internas contendo itens que foram modificados desde o último snapshot - potencialmente muito mais barato do que a clonagem de toda a lista Infelizmente, uma vez que não há um padrão "fazer uma imagem imutável" interface [nota que ICloneable não conta, uma vez que um clone de uma lista mutável seria mutável;., enquanto um poderia fazer umainstantâneo imutável encapsulando um clone mutáveis ??em um read-only invólucro, que só funcionam para as coisas que são cloneable, e até mesmo tipos que não são cloneable ainda deve apoiar uma função "snapshot mutável".]

A minha recomendação é retornar uso um ReadOnlyCollection para o cenário diretamente. Isso faz com que o uso explícito ao usuário chamando.

Normalmente, sugiro usar a interface apropriada. Mas, dado que o .NET Framework não tem atualmente um IReadOnlyCollection adequado, você deve ir com o tipo ReadOnlyCollection.

Além disso, você deve estar ciente ao usar ReadOnlyCollection, porque não é realmente somente leitura: imutabilidade e ReadOnlyCollection

Às vezes, você pode querer usar uma interface, talvez porque você quer zombar a coleção durante testes de unidade. Por favor, veja o meu blogue entrada para adicionar sua própria interface para ReadOnlyCollection usando um adaptador.

Eu normalmente retornar um IEnumerable<T>.

Depois de fazer uma coleção somente leitura (para métodos como Add, Remove e Clear não funcionam mais) não há muito deixou que uma coleção suportes que um enumeráveis ??não -. Apenas Count e Contains, acredito

Se os consumidores de sua classe precisa realmente de elementos tratar como eles estão em uma coleção, é fácil o suficiente para passar um IEnumerable ao construtor de List<T>.

Voltar a T []:

private ICollection<T> items;

public T[] Items
{
    get { return new List<T>(items).ToArray(); }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top