CodeGym /Corsi /C# SELF /Contratto per dizionario: ...

Contratto per dizionario: IDictionary<TKey, TValue>

C# SELF
Livello 28 , Lezione 4
Disponibile

1. Introduzione

Immagina: hai appena trovato lavoro in un laboratorio segreto che studia i gatti. Ti danno un compito — creare un dizionario elettronico dei gatti, dove puoi scoprire velocemente l'età, il colore e la lunghezza della coda di un gatto in base al suo nome. La soluzione pronta già esiste — è Dictionary<string, Cat>. Ma ecco il problema: più tardi il capo dice che per alcune razze rare serve che il dizionario mantenga l'ordine di inserimento, e a volte deve anche essere cancellato secondo una logica speciale.

E se dovessi scrivere un metodo che accetta qualsiasi "dizionario di gatti"? Non importa quale classe concreta — l'importante è che supporti le operazioni base "chiave-valore". Ed è qui che entra in gioco l'interfaccia IDictionary<TKey, TValue>.

IDictionary<TKey, TValue> è un contratto generico che definisce cos'è un dizionario in .NET. Non è una classe concreta, ma un'interfaccia, cioè un insieme di regole che ogni vero dizionario deve rispettare:

  • Ricerca veloce per chiave
  • Aggiunta e rimozione di coppie "chiave-valore"
  • Iterazione su tutte le coppie
  • Controllo dell'esistenza di una chiave

Se Java fosse esistita nel Medioevo, i suoi cavalieri invece delle spade contro i draghi avrebbero brandito chiavi e valori. E gli sviluppatori C# avrebbero semplicemente implementato IDictionary<TKey, TValue> — e il drago (cioè il tuo codice) sarebbe stato sconfitto.

2. Tabella dell'interfaccia IDictionary

Diamo un'occhiata alle principali "promesse" (membri) di questa interfaccia:

Membro dell'interfaccia Tipo Descrizione
this[TKey key]
Proprietà Indicizzatore. Permette di ottenere o impostare il valore associato a una chiave specifica. In lettura: se la chiave non esiste, lancia KeyNotFoundException. In scrittura: se la chiave non esiste, aggiunge una nuova coppia; se la chiave esiste, aggiorna il valore. Importante: è il modo più comune di lavorare con i dizionari.
ICollection<TKey> Keys
Proprietà Restituisce una collezione che contiene tutte le chiavi nel dizionario. Permette di iterare solo sulle chiavi.
ICollection<TValue> Values
Proprietà Restituisce una collezione che contiene tutti i valori nel dizionario. Permette di iterare solo sui valori.
Add(TKey key, TValue value)
Metodo Aggiunge la chiave e il valore specificati al dizionario. Se la chiave esiste già, genera ArgumentException.
ContainsKey(TKey key)
Metodo Determina se il dizionario contiene un elemento con la chiave specificata. Restituisce true se la chiave è trovata; altrimenti — false. Molto utile per evitare errori quando si tenta di accedere a una chiave inesistente tramite l'indicizzatore.
Remove(TKey key)
Metodo Rimuove l'elemento con la chiave specificata dal dizionario. Restituisce true se l'elemento è stato trovato e rimosso con successo; altrimenti — false (ad esempio, se la chiave non è stata trovata).
TryGetValue(TKey key, out TValue value)
Metodo Ottiene il valore associato alla chiave specificata. È un modo sicuro per ottenere un valore se non sei sicuro che la chiave esista. Restituisce true se la chiave è trovata e value contiene il valore corrispondente; altrimenti — false e value conterrà il valore di default per TValue. Questo metodo non lancia eccezioni, il che lo rende molto popolare nel codice reale.

3. Membri principali dell'interfaccia IDictionary<TKey, TValue>

E ora — la parte più importante! Vediamo cosa c'è dentro l'interfaccia IDictionary<TKey, TValue> e impariamo a usare questo "contratto" nel tuo codice.


public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>
{
    TValue this[TKey key] { get; set; } // Indicizzatore per accesso tramite chiave
    ICollection<TKey> Keys { get; }
    ICollection<TValue> Values { get; }
    void Add(TKey key, TValue value); // Aggiungi una nuova coppia (la chiave non deve esistere)
    bool ContainsKey(TKey key); // Esiste questa chiave?
    bool Remove(TKey key); // Rimuovi tramite chiave
    bool TryGetValue(TKey key, out TValue value); // Ottieni valore in modo sicuro
}

Vediamo i punti principali:

Indicizzatore [key]

Permette di ottenere e impostare valori tramite chiave:

dictionary["Barsik"] = new Cat("Barsik", 2);

Proprietà Keys e Values

Permettono di ottenere la collezione di tutte le chiavi o di tutti i valori nel dizionario.

foreach (var name in dictionary.Keys)
{
    Console.WriteLine(name);
}

Metodi Add, Remove, ContainsKey, TryGetValue

  • Add(key, value) — aggiungi una nuova coppia
  • Remove(key) — rimuovi tramite chiave
  • ContainsKey(key) — controlla se la chiave esiste
  • TryGetValue(key, out value) — ottieni valore in modo sicuro (senza eccezione se la chiave non esiste)

4. Uso di IDictionary<TKey, TValue> nella pratica

Metodi universali

Supponiamo che tu stia scrivendo una funzione che deve lavorare con un dizionario, ma non vuole sapere quale classe c'è dentro: un normale Dictionary, SortedDictionary, o magari qualcuno ha implementato il proprio "cripto-dizionario".

Dichiari il parametro come IDictionary<TKey, TValue>:


static void PrintDictionary<TKey, TValue>(IDictionary<TKey, TValue> someDictionary)
{
    foreach (var pair in someDictionary)
    {
        Console.WriteLine($"{pair.Key}: {pair.Value}");
    }
}

Ora il tuo metodo accetta qualsiasi dizionario! Sotto il cofano può esserci qualsiasi cosa — anche un dizionario che cripta i valori, se ti piace vivere pericolosamente.

Uso di IDictionary per passare parametri

Supponiamo che tu stia creando un'app per la gestione dei gatti e vuoi che il tuo metodo funzioni con tutti i possibili dizionari di impostazioni, non solo con una classe specifica. Ecco come si fa:


void SetCatParameters(IDictionary<string, string> parameters)
{
    if (parameters.ContainsKey("color"))
    {
        Console.WriteLine($"Colora il gatto di: {parameters["color"]}");
    }
}

Un'unica firma — più implementazioni

Spieghiamo con una tabella pratica:

Classe della collezione Implementa IDictionary<TKey,TValue> Caratteristiche
Dictionary<TKey, TValue>
✅ Sì Ricerca veloce, chiavi in ordine casuale
SortedDictionary<TKey,TValue>
✅ Sì Le chiavi sono ordinate automaticamente
SortedList<TKey, TValue>
✅ Sì Le chiavi sono ordinate, più efficiente in memoria
(Classe personalizzata che implementa l'interfaccia) ✅ Sì Qualsiasi logica tu voglia, ma devi rispettare il contratto

5. Relazione con altre interfacce di collezione

Per i veri geek: l'interfaccia IDictionary<TKey, TValue> eredita da ICollection<KeyValuePair<TKey, TValue>> e IEnumerable<KeyValuePair<TKey, TValue>>. Questo significa che qualsiasi dizionario può essere:

  • Iterato con foreach sulle coppie chiave-valore,
  • Aggiunto e rimosso tramite i metodi della collezione,
  • Ottenere il numero di elementi.

foreach (var entry in myDictionary)
{
    Console.WriteLine($"{entry.Key} => {entry.Value}");
}

6. Caratteristiche e errori tipici

Lavorare con l'indicizzatore

L'errore più comune dei principianti: tentare di ottenere un elemento tramite una chiave che non esiste genera un'eccezione KeyNotFoundException.


var value = myDictionary["NemaTakogoKlyucha"]; // Boom!

Quindi è sempre meglio usare TryGetValue:


if (myDictionary.TryGetValue("Murzik", out var cat))
{
    Console.WriteLine($"Gatto trovato: {cat}");
}
else
{
    Console.WriteLine($"Gatto non trovato!");
}

Aggiunta di una chiave già esistente

Se chiami Add per una chiave che già esiste, ottieni ArgumentException. Se vuoi "aggiungere o aggiornare", usa l'indicizzatore:


// Aggiunge se non esiste, aggiorna se esiste
myDictionary["Murka"] = new Cat("Murka", 5);

Iterazione e modifica

Non provare a modificare il dizionario (ad esempio, rimuovere elementi) direttamente in un ciclo foreach: otterrai un'eccezione. Se devi rimuovere qualcosa, prima raccogli la lista delle chiavi da eliminare, poi rimuovile in un ciclo separato:


// Modo sicuro per rimuovere elementi
var keysToRemove = new List<string>();
foreach (var pair in myDictionary)
{
    if (pair.Value.Age > 10) // Condizione per la rimozione
    {
        keysToRemove.Add(pair.Key);
    }
}

foreach (var key in keysToRemove)
{
    myDictionary.Remove(key);
}
1
Sondaggio/quiz
Contratto per le collezioni, livello 28, lezione 4
Non disponibile
Contratto per le collezioni
Interfacce base delle collezioni
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION