1. Introdução
Imagina só: tu conseguiu um trampo num laboratório secreto de estudos de gatinhos. Te deram a missão — criar um dicionário eletrônico de gatos, onde pelo nome tu descobre rapidinho a idade, cor e tamanho do rabo do gato. Já tem uma solução pronta — é o Dictionary<string, Cat>. Mas aí o chefe chega e fala que pra umas raças raras o dicionário tem que manter a ordem de inserção, e às vezes ainda remover de um jeito especial.
E se tu precisar escrever um método que aceite qualquer “dicionário de gatos”? Não importa a classe exata — o que importa é que ele suporte as operações básicas de “chave-valor”. É aí que entra a interface IDictionary<TKey, TValue>.
IDictionary<TKey, TValue> é tipo um contrato geral que define o que é um dicionário no .NET. Não é uma classe concreta, é uma interface, ou seja, um conjunto de regras que qualquer dicionário de verdade tem que seguir:
- Busca rápida pela chave
- Adicionar e remover pares “chave-valor”
- Percorrer todos os pares
- Checar se uma chave existe
Se Java existisse na Idade Média, os cavaleiros dela iam lutar contra dragões com chaves e valores no lugar de espadas. Já os devs de C# só iam implementar IDictionary<TKey, TValue> — e o dragão (ou seja, teu código) tava derrotado.
2. Tabela da interface IDictionary
Bora ver as principais “promessas” (membros) dessa interface:
| Membro da interface | Tipo | Descrição |
|---|---|---|
|
Propriedade | Indexador. Permite pegar ou definir o valor associado a uma chave específica. Ao ler: se a chave não existe, lança KeyNotFoundException. Ao escrever: se a chave não existe, adiciona um novo par; se já existe, atualiza o valor. Importante: esse é o jeito mais comum de usar dicionários. |
|
Propriedade | Retorna uma coleção com todas as chaves do dicionário. Dá pra percorrer só as chaves. |
|
Propriedade | Retorna uma coleção com todos os valores do dicionário. Dá pra percorrer só os valores. |
|
Método | Adiciona a chave e valor informados no dicionário. Se a chave já existe, gera ArgumentException. |
|
Método | Verifica se o dicionário tem um elemento com a chave informada. Retorna true se achou; senão — false. Isso é muito útil pra evitar erro quando tu tenta acessar uma chave que não existe pelo indexador. |
|
Método | Remove o elemento com a chave informada do dicionário. Retorna true se achou e removeu; senão — false (tipo, se a chave não existia). |
|
Método | Pega o valor associado à chave informada. Esse é o jeito seguro de pegar um valor quando tu não sabe se a chave existe. Retorna true se achou a chave e value tem o valor certo; senão — false, e value fica com o valor padrão de TValue. Esse método não lança exceção, por isso é super usado na vida real. |
3. Principais membros da interface IDictionary<TKey, TValue>
Agora sim, bora pro que interessa! Vamos ver o que tem dentro da interface IDictionary<TKey, TValue> e aprender a usar esse “contrato” no teu código.
public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>
{
TValue this[TKey key] { get; set; } // Indexador pra acessar pela chave
ICollection<TKey> Keys { get; }
ICollection<TValue> Values { get; }
void Add(TKey key, TValue value); // Adiciona um novo par (a chave não pode existir)
bool ContainsKey(TKey key); // Tem essa chave?
bool Remove(TKey key); // Remove pela chave
bool TryGetValue(TKey key, out TValue value); // Pega o valor de forma segura
}
Bora destrinchar os pontos principais:
Indexador [key]
Permite pegar e definir valores pela chave:
dictionary["Barsik"] = new Cat("Barsik", 2);
Propriedades Keys e Values
Permitem pegar a coleção de todas as chaves ou todos os valores do dicionário.
foreach (var name in dictionary.Keys)
{
Console.WriteLine(name);
}
Métodos Add, Remove, ContainsKey, TryGetValue
- Add(key, value) — adiciona um novo par
- Remove(key) — remove pela chave
- ContainsKey(key) — verifica se a chave existe
- TryGetValue(key, out value) — pega o valor de forma segura (sem exceção se não tiver a chave)
4. Usando IDictionary<TKey, TValue> na prática
Métodos genéricos
Digamos que tu tá escrevendo uma função que tem que funcionar com qualquer dicionário, mas não quer saber qual classe tá por trás: pode ser um Dictionary normal, um SortedDictionary, ou até alguém inventou um “dicionário cripto doidão”.
Tu declara o parâmetro como IDictionary<TKey, TValue>:
static void PrintDictionary<TKey, TValue>(IDictionary<TKey, TValue> someDictionary)
{
foreach (var pair in someDictionary)
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}
}
Agora teu método aceita qualquer dicionário! Por baixo dos panos pode ser qualquer coisa — até um dicionário que criptografa os valores, se tu curtir esse tipo de emoção.
Usando IDictionary pra passar parâmetros
Imagina que tu tá fazendo um app pra registrar gatinhos, e quer que teu método funcione com qualquer dicionário de configurações, não só uma classe específica. Olha só como fica:
void SetCatParameters(IDictionary<string, string> parameters)
{
if (parameters.ContainsKey("color"))
{
Console.WriteLine($"Pinte o gatinho de cor: {parameters["color"]}");
}
}
Uma assinatura — várias implementações
Explicando com uma tabela marota:
| Classe da coleção | Implementa IDictionary<TKey,TValue> | Características |
|---|---|---|
|
✅ Sim | Busca rápida, chaves em ordem aleatória |
|
✅ Sim | Chaves são ordenadas automaticamente |
|
✅ Sim | Chaves ordenadas, mais econômico em memória |
| (Sua própria classe que implementa a interface) | ✅ Sim | Qualquer lógica tua, mas tem que seguir o contrato |
5. Relação com outras interfaces de coleção
Pra quem curte detalhes: a interface IDictionary<TKey, TValue> herda de ICollection<KeyValuePair<TKey, TValue>> e IEnumerable<KeyValuePair<TKey, TValue>>. Isso significa que qualquer dicionário pode:
- Ser percorrido com foreach pelos pares chave-valor,
- Adicionar e remover pares usando métodos da coleção,
- Pegar a quantidade de elementos.
foreach (var entry in myDictionary)
{
Console.WriteLine($"{entry.Key} => {entry.Value}");
}
6. Particularidades e erros comuns
Trabalhando com o indexador
Erro clássico de iniciante: tentar pegar um elemento por uma chave que não existe vai lançar KeyNotFoundException.
var value = myDictionary["NemaTakogoKlyucha"]; // Boom!
Por isso é sempre melhor usar TryGetValue:
if (myDictionary.TryGetValue("Murzik", out var cat))
{
Console.WriteLine($"Achou o gatinho: {cat}");
}
else
{
Console.WriteLine($"Gatinho não encontrado!");
}
Adicionar uma chave que já existe
Se tu chamar Add pra uma chave que já existe, vai tomar ArgumentException. Se quiser “adicionar ou atualizar”, usa o indexador:
// Adiciona se não tem, atualiza se já tem
myDictionary["Murka"] = new Cat("Murka", 5);
Percorrer e modificar
Não tenta modificar o dicionário (tipo, remover elementos) direto num foreach: vai dar exceção. Se precisar remover algo, primeiro monta uma lista de chaves pra remover, depois remove num loop separado:
// Jeito seguro de remover elementos
var keysToRemove = new List<string>();
foreach (var pair in myDictionary)
{
if (pair.Value.Age > 10) // Condição pra remover
{
keysToRemove.Add(pair.Key);
}
}
foreach (var key in keysToRemove)
{
myDictionary.Remove(key);
}
GO TO FULL VERSION