Skip to main content

Guia Completo sobre List, IList, ICollection, IEnumerable e Outras Estruturas no C#

  • Guia Completo sobre List, IList, ICollection, IEnumerable e Outras Estruturas no C#
warning

Dicas

  • Se for fazer apenas 1 iteração usar o IEnumerable, caso tenhas várias usar o List. O IEnumerable só 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(como AsEnumerable()) e To(como ToList()). Os métodos iniciados com Toexigem uma conversão como acima (isto é, podem afetar o desempenho), e os métodos iniciados com Asnã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

alt text

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 Count para 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> e ICollection<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> e Dictionary<TKey, TValue> para operações rápidas de pesquisa.
  • Use Stack<T> e Queue<T> para estruturas de controle de fluxo.
  • Use LinkedList<T> quando precisar de eficiência em inserções e remoções.