Qual é a diferença entre Lista (de T) e Coleção (de T)?

92

Já os vi usados ​​de muitas maneiras semelhantes e estou preocupado em seguir um caminho no design que é irreversível se eu não entender isso melhor. Além disso, estou usando o .NET.

Anthony Potts
fonte

Respostas:

50

Collection<T>é um invólucro personalizável IList<T>. Embora IList<T>não seja lacrado, não fornece pontos de personalização. Collection<T>Os métodos de são delegados por padrão aos IList<T>métodos padrão , mas podem ser facilmente substituídos para fazer o que você deseja. Também é possível conectar eventos dentro de um Collection<T>que eu não acredito que poderia ser feito com um IList.

Resumindo, é muito mais fácil estendê-lo após o fato, o que poderia significar muito menos refatoração.

Adam Lassek
fonte
@Marc Gravell, @Adam Lassek: Não podemos fazer a mesma coisa com um List ocultando o método InsertItem (...) com um void público new InsertItem (...) e depois chamando o base.InsertItem (.. .) de dentro ? Ainda assim, não quebraria o contrato. (o nome é 'Inserir' na lista, mas mesmo assim). Então, qual é o grande problema em manter as Coleções <T>?
DeeStackOverflow
4
@DeeStackOverflow - porque o método esconderijo não será usada por qualquer código que usa uma API diferente - ou seja, qualquer coisa que olha para IList, IList<T>, List<T>etc. Em suma, você não tem idéia se ele vai ser chamado. O polimorfismo corrige isso.
Marc Gravell
@AdamLassek: Você pode querer adicionar em sua resposta sobre ObservableCollection<T>como um exemplo onde os métodos são substituídos para notificar sobre mudanças.
Kiran Challa de
84

Em C #, existem três conceitos para representar um pacote de objetos. Em ordem crescente de recursos, eles são:

  • Enumerável - não ordenado, não modificável
  • Coleção - pode adicionar / remover itens
  • Lista - permite que os itens tenham um pedido (acesso e remoção por índice)

Enumerable não tem ordem. Você não pode adicionar ou remover itens do conjunto. Você não pode nem mesmo obter uma contagem dos itens no conjunto. Ele permite que você acesse estritamente cada item do conjunto, um após o outro.

A coleção é um conjunto modificável. Você pode adicionar e remover objetos do conjunto, você também pode obter a contagem de itens no conjunto. Mas ainda não há ordem, e porque não há ordem: não há como acessar um item por índice, nem há como classificar.

Lista é um conjunto ordenado de objetos. Você pode classificar a lista, acessar itens por índice, remover itens por índice.

Na verdade, ao olhar para as interfaces desses, eles se baseiam um no outro:

  • interface IEnumerable<T>

    • GetEnumeration<T>
  • interface ICollection<T> : IEnumerable<T>

    • Add
    • Remove
    • Clear
    • Count
  • interface IList<T> = ICollection<T>

    • Insert
    • IndexOf
    • RemoveAt

Ao declarar variáveis ​​ou parâmetros de método, você deve escolher usar

  • IEnumerable
  • ICollection
  • IList

com base em conceitualmente você precisa fazer com o conjunto de objetos.

Se você só precisa ser capaz de fazer algo com todos os objetos em uma lista, você só precisa IEnumerable:

void SaveEveryUser(IEnumerable<User> users)
{
    for User u in users
      ...
}

Você não se importa se os usuários são mantidos em um List<T>, Collection<T>, Array<T>ou qualquer outra coisa. Você só precisa da IEnumerable<T>interface.

Se você precisar adicionar, remover ou contar os itens de um conjunto, use uma Coleção :

ICollection<User> users = new Collection<User>();
users.Add(new User());

Se você se preocupa com uma ordem de classificação e precisa que a ordem esteja correta, use uma Lista :

IList<User> users = FetchUsers(db);

Em forma de gráfico:

| Feature                | IEnumerable<T> | ICollection<T> | IList<T> |
|------------------------|----------------|----------------|----------|
| Enumerating items      | X              | X              | X        |
|                        |                |                |          |
| Adding items           |                | X              | X        |
| Removing items         |                | X              | X        |
| Count of items         |                | X              | X        |
|                        |                |                |          |
| Accessing by index     |                |                | X        |
| Removing by indexx     |                |                | X        |
| Getting index of item  |                |                | X        |

O List<T>e Collection<T>em System.Collections.Genericduas classes que implementam estas interfaces; mas eles não são as únicas classes:

  • ConcurrentBag<T>é uma bolsa ordenada de objetos ( IEnumerable<T>)
  • LinkedList<T>é uma bolsa onde você não tem permissão para acessar itens por index ( ICollection); mas você pode adicionar e remover arbitrariamente itens da coleção
  • SynchronizedCollection<T> em uma coleção ordenada, onde você pode adicionar / remover itens por índice

Então você pode mudar facilmente:

IEnumerable<User> users = new SynchronizedCollection<User>();

SaveEveryUser(users);

tl; dr

  • Enumerável - itens de acesso, não ordenados, não modificáveis
  • Coleção - pode ser modificada (adicionar, excluir, contar)
  • Lista - pode acessar por índice

Escolha o conceito de que precisa e, em seguida, use a classe correspondente.

Ian Boyd
fonte
11
O OP perguntou sobre os tipos de concreto, e você comparou as interfaces. O tipo concreto Collection <T> implementa IList <T> e tem acesso por recursos de índice.
JJS
2
A resposta é boa, mas desviada da pergunta. Não é possível ajustar sua resposta para as classes Collection <T> e List <T>, quero dizer, da pergunta prospectiva, se eu tentar validar seu ponto, elas simplesmente não justificam. Para uma resposta de propósito geral, você pode estar certo de que a coleção não é ordenada, portanto, nenhuma indexação, mas a lista é ordenada de forma que a inserção seja possível em um determinado índice.
Kylo Ren
e se eu tivesse recursos de ICollection <T> e também solrting e encontrar possibilidades?
2
Se a lista está ordenada e a coleção não tem ordem, isso seria uma grande diferença funcional para orientar facilmente um novo aluno (como eu) na escolha. Mas espere, por que você diz que uma coleção não tem ordem? Ele fornece os métodos IndexOf () e RemoveAt () , então é ordenado, não é? Eu perdi algo aqui?
RayLuo
1
@RayLuo estou me referindo especificamente a ICollection<T>e IList<T>. Diferentes implementações concretas podem se comportar de maneira diferente. Por exemplo, se você acessar um List<T>por meio de sua IEnumerable<T>interface, não terá como adicionar, remover, classificar ou contar itens na lista.
Ian Boyd
43

List<T>destina-se ao uso interno no código do aplicativo. Você deve evitar escrever APIs públicas que aceitam ou retornam List<T>(em vez disso, considere usar uma superclasse ou uma interface de coleção).

Collection<T> serve uma classe base para coleções personalizadas (embora possa ser usada diretamente).

Considere usar Collection<T>em seu código, a menos que haja recursos específicos de List<T>que você precisa.

Os itens acima são apenas recomendações.

[Adaptado de: Framework Design Guidelines, Second Edition]

Arnold Zokas
fonte
É importante notar que os tipos que usam qualquer tipo de objeto mutável para encapsular seu próprio estado devem evitar o retorno de objetos desse tipo, a menos que os objetos em questão tenham um meio de notificar seu proprietário quando são mutados, ou o nome do método que retorna o objeto implica claramente que está retornando uma nova instância. Observe que para, por exemplo, um Dictionary<string, List<string>>retornar List<string>está bem, uma vez que o estado do dicionário apenas encapsula o identidades das listas nele, ao invés de seu conteúdo.
supercat
37

List<T>é um contêiner muito comumente visto, porque é muito versátil (com muitos métodos úteis como Sort, Findetc) - mas não tem pontos de extensão se você quiser sobrescrever qualquer um dos comportamentos (verifique os itens na inserção, por exemplo).

Collection<T>é um wrapper em torno de qualquer IList<T>(assumindo como padrão List<T>) - ele tem os pontos de extensão ( virtualmétodos), mas não tantos métodos de suporte como Find. Por causa da indireção, é um pouco mais lento do que List<T>, mas não muito.

Com LINQ, os métodos extras em List<T> tornam-se menos importante, já que LINQ-to-Objects tende a fornecê-los de qualquer maneira ... por exemplo First(pred), OrderBy(...), etc.

Marc Gravell
fonte
6
Collection <T> carece de método foreach, mesmo no Linq-to-Objects.
tuinstoel
7
@tuinstoel - mas é trivial adicionar.
Marc Gravell
12

Listar é mais rápido.

Faça por exemplo

private void button1_Click(object sender, EventArgs e)
{
  Collection<long> c = new Collection<long>();
  Stopwatch s = new Stopwatch();
  s.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    c.Add(i);
  }
  s.Stop();
  MessageBox.Show("collect " + s.ElapsedMilliseconds.ToString());

  List<long> l = new List<long>();
  Stopwatch s2 = new Stopwatch();
  s2.Start();
  for (long i = 0; i <= 10000000; i++)
  {
    l.Add(i);
  }
  s2.Stop();
  MessageBox.Show("lis " + s2.ElapsedMilliseconds.ToString());


}

na minha máquina List<>é quase duas vezes mais rápido.

Editar

Não consigo entender por que as pessoas estão rejeitando isso. Tanto em minha máquina de trabalho quanto em minha máquina doméstica, o código List <> é 80% mais rápido.

tuinstoel
fonte
1
Como é mais rápido? Olho para cima? Inserção? Remoção? Procurar? Por que é mais rápido?
Doug T.
17
A lista tem menos letras para digitar do que a coleção :)
RedFilter
1
A coleta tem menos métodos. Portanto, é mais rápido. QED. (brincando, eu não estou trollando)
Ray
2
Tentei na minha máquina e a lista é cerca de 20% mais rápida. Estaria interessado em alguma discussão sobre o porquê disso. Talvez a lista seja melhor com alocação de memória.
Ray
10
Os métodos de lista não são herdáveis, portanto, não há verificações para ver se eles foram herdados; Os métodos da coleção são herdáveis. A vantagem é que você pode usar Collection como uma classe base para herdar e criar uma Collection personalizada.
Richard Gadsden,
11

A lista representa uma coleção em que a ordem dos itens é importante. Ele também suporta métodos de classificação e pesquisa. A coleção é uma estrutura de dados mais geral que faz menos suposições sobre os dados e também suporta menos métodos para manipulá-los. Se você deseja expor uma estrutura de dados customizada, provavelmente deve estender a coleção. Se você precisa manipular dados sem expor a estrutura de dados, uma lista é provavelmente o caminho mais conveniente.

Manu
fonte
4

Esta é uma daquelas questões da pós-graduação. Uma coleção de T é meio abstrata; pode haver uma implementação padrão (não sou um cara .net / c #), mas uma coleção terá operações básicas como adicionar, remover, iterar e assim por diante.

A lista de T implica alguns detalhes sobre essas operações: add deve levar um tempo constante, remove deve levar um tempo proporcional ao número de elementos, getfirst deve ser um tempo constante. Em geral, uma lista é um tipo de coleção, mas uma coleção não é necessariamente um tipo de lista.

Charlie Martin
fonte
4

Hanselman fala : " Collection<T>parece uma lista, e tem até um List<T>interno. CADA método único delega para o interno List<T>. Inclui uma propriedade protegida que expõe o List<T>."

EDIT: Collection<T>não existe em System.Generic.Collections .NET 3.5. Se você migrar do .NET 2.0 para 3.5, você precisará alterar algum código se estiver usando muitoCollection<T> objetos, a menos que esteja faltando algo óbvio ...

EDIT 2: Collection<T>agora está no namespace System.Collections.ObjectModel no .NET 3.5. O arquivo de ajuda diz o seguinte:

"O namespace System.Collections.ObjectModel contém classes que podem ser usadas como coleções no modelo de objeto de uma biblioteca reutilizável. Use essas classes quando propriedades ou métodos retornarem coleções."

Tad Donaghe
fonte
4

Todas essas interfaces são herdadas de IEnumerable, o que você deve ter certeza de entender. Essa interface basicamente permite que você use a classe em uma instrução foreach (em C #).

  • ICollectioné a mais básica das interfaces que você listou. É uma interface enumerável que oferece suporte a um Counte é tudo.
  • IListé tudo o que ICollectionexiste, mas também suporta adicionar e remover itens, recuperar itens por índice, etc. É a interface mais comumente usada para "listas de objetos", o que eu sei é vago.
  • IQueryableé uma interface enumerável que oferece suporte a LINQ. Você sempre pode criar um IQueryablede um IList e usar LINQ to Objects, mas também pode ser IQueryableusado para execução adiada de instruções SQL em LINQ to SQL e LINQ to Entities.
  • IDictionaryé um animal diferente no sentido de que é um mapeamento de chaves exclusivas para valores. Também é enumerável no sentido de que você pode enumerar os pares chave / valor, mas, caso contrário, serve a um propósito diferente dos outros que você listou
Raj Gupta
fonte
ICollection oferece suporte para adicionar / remover / limpar: msdn.microsoft.com/en-us/library/…
amnesia
4

De acordo com o MSDN, List (Of T) .Add é "uma operação O (n)" (quando "Capacity" é excedida), enquanto Collection (Of T) .Add é sempre "uma operação O (1)". Isso seria compreensível se List fosse implementado usando um Array e Collection a Linked List. No entanto, se fosse esse o caso, seria de se esperar que Collection (Of T) .Item fosse "uma operação O (n)". Mas - é - não !?! Collection (Of T) .Item é "uma operação O (1)" assim como List (Of T) .Item.

Além disso, "tuinstoel" s "Dec 29 '08 at 22:31" post acima afirma que os testes de velocidade mostram List (Of T). Adicione para ser mais rápido que Collection (Of T) .Add que reproduzi com Long's e String's. Embora eu só tenha ficado ~ 33% mais rápido contra seus 80% reivindicados, de acordo com o MSDN, deveria ter sido o oposto e "n" vezes!?!

Tom
fonte
3

Ambos implementam as mesmas interfaces, portanto, eles se comportarão da mesma maneira. Talvez eles sejam implementados de forma diferente internamente, mas isso teria que ser testado.

As únicas diferenças reais que vejo são os namespaces e o fato de que Collection<T>está marcado com ComVisibleAttribute(false), portanto, o código COM não pode usá-lo.

OwenP
fonte
Eles implementam interfaces diferentes - List <T> implementa IList <T>, onde Collection <T> não.
Bevan
@Bevan tente em c #, ambos implementam o mesmo conjunto de interfaces
Kylo Ren
1
Isso é um interessante @KyloRen mudança - eles fazem agora ambos implementar o mesmo conjunto de interfaces; este não era o caso em '08.
Bevan
1
@Bevan interessante. Não tenho certeza de qual foi a razão de duas classes diferentes, uma com apenas alguns métodos extras.
Kylo Ren
3

Além de outras perguntas, eu compilei uma visão geral rápida de listas genéricas e recursos de coleção. A coleção é um subconjunto limitado da Lista:

* =  presente
o = parcialmente presente

Coleção de Propriedade / Método < T > Lista < T > --------------------------------------- -------      

Add()                *              *
AddRange()                          *
AsReadOnly()                        *
BinarySearch()                      *
Capacity                            *
Clear()              *              *
Contains()           *              *
ConvertAll()                        *
CopyTo()             o              *
Count                *              *
Equals()             *              *
Exists()                            *
Find()                              *
FindAll()                           *
FindIndex()                         *
FindLast()                          *
FindLastIndex()                     *
ForEach()                           *
GetEnumerator()      *              *
GetHashCode()        *              *
GetRange()                          *
GetType()            *              *
IndexOf()            o              *
Insert()             *              *
InsertRange()                       *
Item()               *              *
LastIndexOf()                       *
New()                o              *
ReferenceEquals()    *              *
Remove()             *              *
RemoveAll()                         *
RemoveAt()           *              *
RemoveRange()                       *
Reverse()                           *
Sort()                              *
ToArray()                           *
ToString()           *              *
TrimExcess()                        *
TrueForAll()                        *
miroxlav
fonte