Guia Completo sobre List, IList, ICollection, IEnumerable e Outras Estruturas no C#
- Guia Completo sobre List, IList, ICollection, IEnumerable e Outras Estruturas no C#
Dicas
-
Se for fazer apenas 1 iteração usar o
IEnumerable, caso tenhas várias usar oList. OIEnumerablesó obtém os dados quando realmente precisa deles e ele pode refazer a operação pois ele não mantém os dados na memória. -
List aloca todos os dados na memória
=mais rápido, mas pode ter problemas com GC -
Você notará no LINQ que existem vários métodos que começam com
As(comoAsEnumerable()) eTo(comoToList()). Os métodos iniciados comToexigem uma conversão como acima (isto é, podem afetar o desempenho), e os métodos iniciados comAsnão exigem e apenas exigirão alguma operação simples ou de conversão . -
Quando você da um new em uma lista, automaticamente ele adiciona 4 posições na lista por padrão

1. Introdução
O .NET fornece diversas coleções para manipular conjuntos de dados. As interfaces IEnumerable, ICollection, IList e a classe List<T> desempenham papéis fundamentais na manipulação de listas e sequências de objetos. Além disso, outras estruturas como HashSet<T>, Dictionary<TKey, TValue>, LinkedList<T>, Stack<T>, Queue<T> e SearchValues<T> oferecem diferentes abordagens para armazenamento e recuperação de dados. Este guia explora detalhadamente essas estruturas e suas diferenças.
IEnumerable<T>
O que é?
IEnumerable<T> é a interface mais básica para iteração sobre uma coleção. Ele permite percorrer os elementos, mas não oferece suporte a operações como adição, remoção ou acesso direto por índice.
Características principais:
- Somente leitura: não permite modificar a coleção.
- Iteração sob demanda (Lazy Evaluation): elementos são recuperados conforme necessário.
- Não suporta acesso por índice (
[i]). - Ideal para streaming de dados (banco de dados, arquivos grandes, etc.).
Exemplo de Implementação:
public static IEnumerable<int> GerarNumeros()
{
for (int i = 1; i <= 5; i++)
{
yield return i;
}
}
Quando Usar?
- Quando você só precisa iterar sobre os elementos uma vez.
- Quando deseja minimizar o uso de memória, carregando apenas os dados necessários.
ICollection<T>
O que é?
A interface ICollection<T> estende IEnumerable<T> e adiciona suporte para contar elementos, adicionar, remover e verificar se um item existe na coleção.
Características principais:
- Suporta adição e remoção de elementos.
- Mantém a funcionalidade de iteração (
IEnumerable<T>). - Inclui a propriedade
Countpara verificar o número de elementos. - Não oferece acesso direto por índice (
[i]).
Exemplo de Implementação:
ICollection<int> numeros = new List<int> {1, 2, 3};
numeros.Add(4);
numeros.Remove(2);
Console.WriteLine(numeros.Count); // Saída: 3
Quando Usar?
- Quando você precisa modificar a coleção, mas não precisa acessar elementos por índice.
- Quando você precisa verificar rapidamente a quantidade de elementos.
IList<T>
O que é?
A interface IList<T> expande ICollection<T>, adicionando suporte para acesso por índice e inserção/remoção em posições específicas.
Características principais:
- Suporta acesso por índice (
[i]). - Permite adição e remoção em qualquer posição.
- É utilizada pela classe
List<T>.
Exemplo de Implementação:
IList<string> nomes = new List<string> {"Ana", "Bruno", "Carlos"};
nomes.Insert(1, "Daniel");
nomes.RemoveAt(2);
Console.WriteLine(nomes[1]); // Saída: Daniel
Quando Usar?
- Quando você precisa modificar elementos e acessar por índice.
- Quando a coleção precisar de ordenação ou inserções em posições específicas.
List<T>
O que é?
A List<T> é uma implementação concreta de IList<T> e ICollection<T>, baseada em um array dinâmico.
Características principais:
- Suporta todas as operações de
IList<T>eICollection<T>. - Muito eficiente para acessos aleatórios (
[i]). - Aloca memória extra para evitar realocações frequentes.
Exemplo de Implementação:
List<int> numeros = new List<int> { 1, 2, 3 };
numeros.Add(4);
numeros.Remove(2);
Console.WriteLine(numeros[1]); // Saída: 3
Quando Usar?
- Quando você precisa de um array dinâmico com acesso rápido por índice.
- Quando os elementos precisam ser ordenados ou modificados frequentemente.
Outras Estruturas de Dados
HashSet<T>
- Armazena elementos únicos e não permite duplicatas.
- Muito eficiente para buscas rápidas.
- Usa código hash para otimizar operações de pesquisa.
var conjunto = new HashSet<int> {1, 2, 3};
conjunto.Add(3); // Não adicionará um valor duplicado
Console.WriteLine(conjunto.Count); // Saída: 3
Dictionary<TKey, TValue>
- Estrutura chave-valor eficiente para buscas rápidas.
var dicionario = new Dictionary<int, string>();
dicionario.Add(1, "João");
Console.WriteLine(dicionario[1]); // Saída: João
// ou
var dict = new Dictionary<string, int>
{
{ "A", 1 },
{ "B", 2 },
{ "C", 3 }
};
LinkedList<T>
- Lista encadeada eficiente para inserções e remoções.
var lista = new LinkedList<int>();
lista.AddLast(10);
lista.AddFirst(5);
Stack<T>
- Estrutura LIFO (Last-In, First-Out).
var pilha = new Stack<int>();
pilha.Push(10);
pilha.Push(20);
Console.WriteLine(pilha.Pop()); // Saída: 20
Queue<T>
- Estrutura FIFO (First-In, First-Out).
var fila = new Queue<int>();
fila.Enqueue(10);
fila.Enqueue(20);
Console.WriteLine(fila.Dequeue()); // Saída: 10
SearchValues<T>
- Estrutura moderna para buscas otimizadas no .NET.
- Permite verificar rapidamente se um conjunto de valores contém determinado item, sendo eficiente para grandes coleções.
using System;
using System.Collections.Frozen;
var searchValues = SearchValues.Create(new[] { "apple", "banana", "cherry" });
if (searchValues.Contains("banana"))
{
Console.WriteLine("Valor encontrado!");
}
else
{
Console.WriteLine("Valor não encontrado.");
}
Conclusão
Cada tipo de coleção tem seu próprio propósito:
- Use
IEnumerable<T>para iteração simples e consultas LINQ. - Use
ICollection<T>quando precisar modificar a coleção, mas sem acesso por índice. - Use
IList<T>se você precisar inserir/remover elementos por índice. - Use
List<T>para uma estrutura flexível e de alto desempenho. - Use
HashSet<T>eDictionary<TKey, TValue>para operações rápidas de pesquisa. - Use
Stack<T>eQueue<T>para estruturas de controle de fluxo. - Use
LinkedList<T>quando precisar de eficiência em inserções e remoções.