Dictionary<TKey, TValue> โ lookup by key
Add, indexing, TryGetValue, ContainsKey โ and why the indexer throws on a missing key.
Keys map to values
var ages = new Dictionary<string, int>();
ages["an"] = 30; // insert or overwrite
ages.Add("binh", 25); // THROWS if "binh" already exists
Console.WriteLine(ages["an"]); // 30 โ THROWS if "an" is absent
The indexer creates or overwrites; Add refuses duplicates. Reading ages["missing"] throws KeyNotFoundException โ the single most common dictionary crash. Two safe reads:
if (ages.TryGetValue("missing", out int age))
Console.WriteLine(age); // out param set only when found
if (ages.ContainsKey("missing")) { ... } // check without reading
TryGetValue is preferred: one lookup instead of two (ContainsKey then indexer), and it gives you the value.
Counting things โ the classic pattern
var votes = new Dictionary<string, int>();
foreach (string ballot in ballots)
{
votes.TryGetValue(ballot, out int n);
votes[ballot] = n + 1; // read-modify-write
}
TryGetValue with out conveniently yields 0 when the key is absent, so the pattern handles first-votes without a branch. Counting, grouping, and deduplicating (next lesson) are the three dictionary superpowers โ every practice challenge here is one of them.
Iteration
foreach (var kv in ages) yields KeyValuePair<string,int> โ read kv.Key/kv.Value. Dictionaries have no defined order; never write logic that depends on enumeration order.