C# Programming Tutorial 0/45 lessons ~6 min read Lesson 23

    Dictionary

    Dictionary<TKey,TValue> provides O(1) average hash-based lookups — essential for caches, indexes, and grouping.

    Course progress0%
    Focus
    10 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Dictionary<TKey,TValue> provides O(1) average hash-based lookups — essential for caches, indexes, and grouping. Keys must be unique with consistent GetHashCode and Equals implementations.

    ConcurrentDictionary handles multi-threaded scenarios. Interviewers ask hash collision handling, why mutable keys are dangerous, and Dictionary vs Lookup vs FrozenDictionary (.NET 8).

    The story

    A currency exchange desk at an airport caches FX rates in memory so tellers get instant quotes. Each rate is keyed by a currency pair like USD→EUR; lookups must be fast and duplicate keys must never silently overwrite without intent.

    Dictionary<TKey, TValue> with a well-defined key type is the standard pattern for in-memory caches in trading and banking apps.

    Understanding the topic

    Key concepts

    • Key-value pairs with unique keys.
    • TryGetValue avoids double lookup.
    • Custom keys need proper Equals/GetHashCode override.
    • Order undefined — use SortedDictionary for order.
    • FrozenDictionary immutable optimized read (.NET 8).
    • Collection initializer: { ['a'] = 1 }.

    Step-by-step explanation

    1. Hash code buckets entries; collision chains or open addressing.
    2. Add throws on duplicate key; TryAdd for idempotent.
    3. Remove by key; Clear empties.
    4. Keys, Values collections are views.
    5. Enumerate KeyValuePair.
    6. EqualityComparer.Default for primitives/strings.

    Practical code example

    In-memory currency rate cache with TryGetValue and record key:

    csharp
    namespace TechLearningPro.Dictionary;
    public readonly record struct CurrencyPair(string From, string To);
    public sealed class FxRateCache
    {
    private readonly Dictionary<CurrencyPair, decimal> _rates = new();
    public bool TryGetRate(string from, string to, out decimal rate)
    {
    var key = new CurrencyPair(from.ToUpperInvariant(), to.ToUpperInvariant());
    return _rates.TryGetValue(key, out rate);
    }
    public void SetRate(string from, string to, decimal rate) =>
    _rates[new CurrencyPair(from.ToUpperInvariant(), to.ToUpperInvariant())] = rate;
    }

    Line-by-line code explanation

    • readonly record struct CurrencyPair(string From, string To) is an immutable value-type key with built-in equality.
    • Dictionary<CurrencyPair, decimal> _rates maps pairs to exchange rates.
    • TryGetRate(string from, string to, out decimal rate) follows the Try-pattern for safe lookups.
    • new CurrencyPair(from.ToUpperInvariant(), to.ToUpperInvariant()) normalizes casing before keying.
    • _rates.TryGetValue(key, out rate) performs a single hash lookup — no double search.
    • return _rates.TryGetValue(...) propagates whether the rate was found.
    • SetRate(...) inserts or updates a rate for a currency pair.
    • _rates[...] = rate uses the indexer to assign the value for the computed key.

    Key takeaway: record struct CurrencyPair gets value-based equality for dictionary keys. TryGetValue is idiomatic — no double lookup.

    Real-world use

    Where you'll use this in production

    • Session stores mapping userId to session data.
    • Configuration key lookup.
    • Grouping counts in analytics dashboards.
    • Memoization caches in algorithms.

    Best practices

    • Always TryGetValue instead of ContainsKey + indexer.
    • Use immutable record keys.
    • Consider FrozenDictionary for static read-heavy maps (.NET 8).
    • ConcurrentDictionary for parallel updates.
    • Do not mutate key objects after insertion.

    Common mistakes

    • Custom class key without GetHashCode override.
    • Assuming enumeration order stable across runs.
    • Using float keys — precision breaks equality.
    • Locking entire Dictionary under contention — use concurrent type.

    Advanced interview questions

    Q1BeginnerDictionary time complexity?
    Average O(1) lookup/add; worst O(n) with poor hash.
    Q2BeginnerTryGetValue vs ContainsKey?
    TryGetValue single lookup; ContainsKey+indexer double.
    Q3IntermediateWhy immutable keys?
    Mutating key changes hash bucket — lost entries.
    Q4IntermediateDictionary vs Lookup?
    Lookup immutable from IGrouping; multiple values per key.
    Q5AdvancedImplement LRU cache with Dictionary.
    Dictionary key→LinkedListNode; LinkedList for order; move on access; evict tail O(1).

    Summary

    Dictionary provides fast key-value lookups. Use TryGetValue and immutable keys. FrozenDictionary and ConcurrentDictionary for specialized needs. Override equality correctly for custom keys. Next: HashSet for unique unordered sets.

    Ready to mark this lesson complete?Track your journey across the entire course.