CodeGym /Courses /C# SELF /Dictionary Contract: IDict...

Dictionary Contract: IDictionary<TKey, TValue>

C# SELF
Level 28 , Lesson 4
Available

1. Introduction

Imagine this: you get a job at a secret cat research lab. Your task is to create an electronic cat dictionary, where you can quickly find out a cat's age, color, and tail size by its name. There's already a ready-made solution — that's Dictionary<string, Cat>. But here's the catch: later your boss says that for some rare breeds, the dictionary needs to keep the order of adding, and sometimes even delete entries with some special logic.

But what if you need to write a method that takes any "cat dictionary"? Doesn't matter which class exactly — what's important is that it supports the basic "key-value" operations. That's where the IDictionary<TKey, TValue> interface comes in.

IDictionary<TKey, TValue> is a general contract that defines what a dictionary is in .NET. It's not a concrete class, but an interface — a set of rules that any real dictionary must follow:

  • Fast lookup by key
  • Adding and removing "key-value" pairs
  • Iterating through all pairs
  • Checking if a key exists

If Java existed in the Middle Ages, its knights would swing keys and values instead of swords against dragons. And C# devs would just implement IDictionary<TKey, TValue> — and the dragon (your code) would be slayed.

2. IDictionary Interface Table

Let's check out the main "promises" (members) of this interface:

Interface Member Type Description
this[TKey key]
Property Indexer. Lets you get or set the value associated with a given key. When reading: if the key isn't found, throws KeyNotFoundException. When writing: if the key isn't found, adds a new pair; if the key exists, updates the value. Important: this is the most common way to work with dictionaries.
ICollection<TKey> Keys
Property Returns a collection containing all the keys in the dictionary. Lets you iterate just the keys.
ICollection<TValue> Values
Property Returns a collection containing all the values in the dictionary. Lets you iterate just the values.
Add(TKey key, TValue value)
Method Adds the given key and value to the dictionary. If the key already exists, throws ArgumentException.
ContainsKey(TKey key)
Method Checks if the dictionary contains an entry with the given key. Returns true if the key is found; otherwise — false. Super useful to avoid errors when trying to access a non-existent key via the indexer.
Remove(TKey key)
Method Removes the entry with the given key from the dictionary. Returns true if the entry was found and removed; otherwise — false (for example, if the key wasn't found).
TryGetValue(TKey key, out TValue value)
Method Gets the value associated with the given key. This is a safe way to get a value if you're not sure the key exists. Returns true if the key is found, and value contains the corresponding value; otherwise — false, and value will have the default value for TValue. This method doesn't throw an exception, which makes it super popular in real code.

3. Main Members of IDictionary<TKey, TValue>

Now for the good stuff! Let's see what's inside the IDictionary<TKey, TValue> interface, and learn how to use this "contract" in your code.


public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>
{
    TValue this[TKey key] { get; set; } // Indexer for key access
    ICollection<TKey> Keys { get; }
    ICollection<TValue> Values { get; }
    void Add(TKey key, TValue value); // Add a new pair (key must not exist) 
    bool ContainsKey(TKey key); // Does this key exist?
    bool Remove(TKey key); // Remove by key
    bool TryGetValue(TKey key, out TValue value); // Safely get value
}

Let's break down the main points:

Indexer [key]

Lets you get and set values by key:

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

Properties Keys and Values

Let you get a collection of all keys or all values in the dictionary.

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

Methods Add, Remove, ContainsKey, TryGetValue

  • Add(key, value) — add a new pair
  • Remove(key) — remove by key
  • ContainsKey(key) — check if key exists
  • TryGetValue(key, out value) — safely get value (no exception if the key doesn't exist)

4. Using IDictionary<TKey, TValue> in Practice

Generic Methods

Say you're writing a function that should work with a dictionary, but doesn't care which class is inside: a regular Dictionary, SortedDictionary, or maybe someone made their own "crypto-collective dictionary".

You declare the parameter as IDictionary<TKey, TValue>:


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

Now your method takes any dictionary! Under the hood it could be anything — even a dictionary that encrypts values, if you're living that kind of wild life.

Using IDictionary for Passing Parameters

Say you're making a cat management app, and you want your method to work with all possible settings dictionaries, not just one specific class. Here's what it looks like:


void SetCatParameters(IDictionary<string, string> parameters)
{
    if (parameters.ContainsKey("color"))
    {
        Console.WriteLine($"Paint the cat with color: {parameters["color"]}");
    }
}

One Signature — Multiple Implementations

Let's explain with a live table:

Collection Class Implements IDictionary<TKey,TValue> Features
Dictionary<TKey, TValue>
✅ Yes Fast lookup, keys in random order
SortedDictionary<TKey,TValue>
✅ Yes Keys are automatically sorted
SortedList<TKey, TValue>
✅ Yes Keys are sorted, more memory efficient
(Your own class implementing the interface) ✅ Yes Any logic you want, but you gotta follow the contract

5. Relationship with Other Collection Interfaces

For the real geeks: the IDictionary<TKey, TValue> interface inherits from ICollection<KeyValuePair<TKey, TValue>> and IEnumerable<KeyValuePair<TKey, TValue>>. That means any dictionary can be:

  • Iterated with foreach by key-value pairs,
  • Add and remove pairs using collection methods,
  • Get the count of elements.

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

6. Features and Typical Mistakes

Working with the Indexer

The most common newbie mistake: trying to get an entry by a missing key will throw a KeyNotFoundException.


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

So it's always better to use TryGetValue:


if (myDictionary.TryGetValue("Murzik", out var cat))
{
    Console.WriteLine($"Found the cat: {cat}");
}
else
{
    Console.WriteLine($"Cat not found!");
}

Adding an Existing Key

If you call Add for a key that already exists, you'll get an ArgumentException. If you want to "add or update", use the indexer:


// Adds if not there, updates if it is
myDictionary["Murka"] = new Cat("Murka", 5);

Iterating and Modifying

Don't try to modify the dictionary (like removing entries) directly in a foreach loop: you'll get an exception. If you need to remove stuff, first collect the keys to remove, then remove them in a separate loop:


// Safe way to remove entries
var keysToRemove = new List<string>();
foreach (var pair in myDictionary)
{
    if (pair.Value.Age > 10) // Condition for removal
    {
        keysToRemove.Add(pair.Key);
    }
}

foreach (var key in keysToRemove)
{
    myDictionary.Remove(key);
}
2
Task
C# SELF, level 28, lesson 4
Locked
Checking for a Key in a Dictionary
Checking for a Key in a Dictionary
1
Survey/quiz
Collection Contract, level 28, lesson 4
Unavailable
Collection Contract
Basic Collection Interfaces
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION