Reading a value by key
To read a value from a Dictionary<TKey, TValue>, put the key in square brackets, using the same indexer you use to store values:
Dictionary<string, int> scores = new Dictionary<string, int>();
scores["Alice"] = 95;
scores["Bob"] = 87;
int aliceScore = scores["Alice"]; // 95
int bobScore = scores["Bob"]; // 87
The result has the dictionary's value type, so for a Dictionary<string, int> you can store it straight into an int. There is no get method to call. Code ported from Java uses get(key), and that doesn't exist on a C# dictionary.
When the key is missing
This is the main difference from other languages. Reading a key that isn't in the dictionary does not give you null or a default value. The indexer throws a KeyNotFoundException:
int diana = scores["Diana"]; // throws KeyNotFoundException
That is deliberate. The indexer assumes the key is there, and a missing key is treated as a bug. When a key might be absent, use one of three safer patterns.
ContainsKey
Ask first, then read:
if (scores.ContainsKey("Alice")) {
Console.WriteLine(scores["Alice"]);
}
This works, but it looks the key up twice, once to check and once to read.
TryGetValue
TryGetValue checks and reads in one call. It returns a bool that says whether the key was found, and hands the value back through an out parameter:
if (scores.TryGetValue("Bob", out int bob)) {
Console.WriteLine(bob); // 87
}
bool found = scores.TryGetValue("Diana", out int diana);
Console.WriteLine(found); // False
Console.WriteLine(diana); // 0
When the key is missing, the out variable is set to the default of the value type: 0 for int, null for a string or other reference type. Always test the returned bool instead of guessing from the value, because a stored value can also be 0.
GetValueOrDefault
When all you want is a fallback, GetValueOrDefault is the shortest form:
int score = scores.GetValueOrDefault("Diana", 0); // 0 when not found
int other = scores.GetValueOrDefault("Diana"); // also 0, the default for int
Without the second argument it falls back to the type's default value. It doesn't add the key to the dictionary.
Choosing between the three
Use the plain indexer when the key must be there and a missing one means a mistake in your program: the exception points straight at the problem. Use TryGetValue when you need to do different things depending on whether the key exists. Use GetValueOrDefault when a sensible fallback value exists, such as 0 for a missing score or an empty string for a missing name.
Keys and values on their own
Sometimes you want every key or every value rather than one lookup. The Keys and Values properties give you each as a collection:
foreach (string name in scores.Keys) {
Console.WriteLine(name + ": " + scores[name]);
}
foreach (int value in scores.Values) {
Console.WriteLine(value);
}
Looping over the dictionary itself, as in foreach (var pair in scores), gives pair.Key and pair.Value together and avoids the extra lookup in the first loop.
Case and spelling
String keys are compared exactly, including case. scores["alice"] is not the same key as scores["Alice"], and with the dictionary above it throws.
The exercise, step by step
The lesson starts with a scores dictionary that already has three students. The task is to read Alice's score from it.
- Declare an
intvariable namedaliceScorebelow the dictionary. - Assign it
scores["Alice"]. The key is the string"Alice", and the value that comes back is 95. It is safe to use the plain indexer, because the dictionary above was built with that key.
Dictionary<string, int> scores = new Dictionary<string, int>();
scores["Alice"] = 95;
scores["Bob"] = 87;
scores["Charlie"] = 72;
int aliceScore = scores["Alice"];
Common mistakes
- Calling
get. C# uses the indexer,scores["Alice"], notscores.get("Alice"). - Expecting
nullfor a missing key. The indexer throws instead. UseTryGetValueorGetValueOrDefaultfor keys that may be absent. - Using the wrong type. An
intvariable can hold the value from aDictionary<string, int>. Declaring it asstringdoesn't compile. - Misspelling or mis-casing the key.
"alice"and"Alice"are different keys. - Reading before storing. If the dictionary doesn't yet hold the key at the moment of the read, the read throws, so keep the assignments above it.
Key takeaways
d[key]reads the value for a key.- A missing key makes the indexer throw
KeyNotFoundException. ContainsKey,TryGetValueandGetValueOrDefaulthandle keys that might be missing.- String keys are case-sensitive.