Existe algum motivo para expor uma coleção interna como um ReadOnlyCollection em vez de um IEnumerable se o código de chamada iterar apenas sobre a coleção?
class Bar
{
private ICollection<Foo> foos;
// Which one is to be preferred?
public IEnumerable<Foo> Foos { ... }
public ReadOnlyCollection<Foo> Foos { ... }
}
// Calling code:
foreach (var f in bar.Foos)
DoSomething(f);
A meu ver, IEnumerable é um subconjunto da interface do ReadOnlyCollection e não permite que o usuário modifique a coleção. Portanto, se a interface IEnumberable for suficiente, essa é a única a ser usada. Essa é uma maneira adequada de argumentar sobre isso ou estou perdendo alguma coisa?
Obrigado / Erik
c#
.net
collections
ienumerable
readonly-collection
Erik Öjebo
fonte
fonte
ReadOnlyCollection
se for paranóico, mas agora não está vinculado a uma implementação específica.Respostas:
Solução mais moderna
A menos que você precise que a coleção interna seja mutável, você pode usar o
System.Collections.Immutable
pacote, alterar seu tipo de campo para ser uma coleção imutável e expô-la diretamente - assumindo queFoo
ela é imutável, é claro.Resposta atualizada para responder à pergunta mais diretamente
Depende de quanto você confia no código de chamada. Se você tiver controle total sobre tudo o que chamará esse membro e garantir que nenhum código será usado:
então, certamente, nenhum dano será causado se você apenas devolver a coleção diretamente. Eu geralmente tento ser um pouco mais paranóico do que isso.
Da mesma forma, como você diz: se você só precisa
IEnumerable<T>
, por que se amarrar a algo mais forte?Resposta original
Se você estiver usando o .NET 3.5, evite fazer uma cópia e evitar a conversão simples usando uma chamada simples para Ignorar:
(Existem muitas outras opções para agrupar trivialmente - o
Skip
mais interessante de Selecionar / Onde é que não há delegado para executar sem sentido para cada iteração.)Se você não estiver usando o .NET 3.5, você pode escrever um invólucro muito simples para fazer a mesma coisa:
fonte
ReadOnlyCollection
para umICollection
e a execução comAdd
êxito. Tanto quanto sei, isso não deveria ser possível. Oevil.Add(...)
deve lançar um erro. dotnetfiddle.net/GII2jWReadOnlyCollection
- lancei umIEnumerable<T>
que na verdade não é somente leitura ... é em vez de expor umReadOnlyCollection
ReadOnlyCollection
vez de umIEnumerable
, a fim de proteger contra o elenco maligno.Se você apenas precisar percorrer a coleção:
devolver IEnumerable é suficiente.
Se você precisar de acesso aleatório aos itens:
Em seguida, envolva-o em ReadOnlyCollection .
fonte
System.Collections.Immutable
como Jon Skeet recomenda é perfeitamente válido quando você expõe algo que nunca vai mudar depois de obter uma referência a ele. Por outro lado, se você estiver expondo uma visão somente leitura de uma coleção mutável, esse conselho ainda será válido, embora eu provavelmente a exponha comoIReadOnlyCollection
(que não existia quando escrevi isso).bar.Foos[17]
comIReadOnlyCollection
. A única diferença éCount
propriedade adicional .public interface IReadOnlyCollection<out T> : IEnumerable<T>, IEnumerable
bar.Foos[17]
, tem que expô-lo comoReadOnlyCollection<Foo>
. Se você deseja saber o tamanho e iterar através dele, exponha-o comoIReadOnlyCollection<Foo>
. Se você não precisa saber o tamanho, useIEnumerable<Foo>
. Existem outras soluções e outros detalhes, mas está além do escopo da discussão dessa resposta específica.Se você fizer isso, nada impedirá que os chamadores convertam o IEnumerable de volta ao ICollection e o modifiquem. O ReadOnlyCollection remove essa possibilidade, embora ainda seja possível acessar a coleção gravável subjacente por meio de reflexão. Se a coleção for pequena, uma maneira fácil e segura de contornar esse problema é retornar uma cópia.
fonte
Evito usar o ReadOnlyCollection, tanto quanto possível, é realmente consideravelmente mais lento do que apenas usar uma lista normal. Veja este exemplo:
fonte
Às vezes, você pode querer usar uma interface, talvez porque queira zombar da coleção durante o teste de unidade. Consulte a entrada do meu blog para adicionar sua própria interface ao ReadonlyCollection usando um adaptador.
fonte