Collections: List<T> and Dictionary<TKey, TValue>
C#'s most commonly used generic collections, and the TryGetValue lookup pattern.
What you'll learn
- Create and grow a `List<T>` with `Add`
- Create a `Dictionary<TKey, TValue>` and look up a value safely with `TryGetValue`
- Explain why `TryGetValue` is preferred over indexing directly when a key might not exist
Explanation
List<T> is C#'s everyday resizable, ordered collection. It's always backed by its own internal array that it manages and resizes for you, so growing it never requires reassigning anything yourself. You create one with new List<string> { "Ada", "Grace" } and grow it with .Add(...). .Count gives you the current number of elements.
Dictionary<TKey, TValue> is C#'s hash map. You can create one with a collection initializer using index syntax: new Dictionary<string, int> { ["Ada"] = 90 }.
Indexing a dictionary directly with someDict["missingKey"] throws a KeyNotFoundException if the key doesn't exist. C#'s safe lookup is TryGetValue: if (scores.TryGetValue("Ada", out int adaScore)) { ... } -- it returns true and sets adaScore if the key exists, or false (with adaScore set to the type's default) if it doesn't, letting you branch on success without risking an exception.
<T> (and <TKey, TValue>) mark List and Dictionary as generic types -- the same List<T> code works for List<int>, List<string>, or a list of any other type, with the compiler enforcing that every element really is that type.
Guided lab
Fill in the blank: the TryGetValue lookup pattern
Fill in the missing keyword required by TryGetValue's second parameter, then predict the output.
using System;
using System.Collections.Generic;
List<string> names = new List<string> { "Ada", "Grace" };
names.Add("Linus");
Dictionary<string, int> scores = new Dictionary<string, int>
{
["Ada"] = 90,
["Grace"] = 85,
};
Console.WriteLine($"names: {string.Join(", ", names)}");
Console.WriteLine($"count: {names.Count}");
if (scores.TryGetValue("Ada", ____ int adaScore))
{
Console.WriteLine($"Ada's score: {adaScore}");
}
if (!scores.TryGetValue("Linus", ____ int linusScore))
{
Console.WriteLine("Linus not found");
}Stuck? Get a hint.
Common mistakes
- Indexing a `Dictionary` directly with `dict[key]` for a key that might not exist, risking an unhandled `KeyNotFoundException` -- use `TryGetValue` instead when the key's presence isn't guaranteed.
- Forgetting `.Add` on a `List<T>` mutates the list in place -- there's nothing to reassign, unlike appending in some other languages.
- Forgetting the `out` keyword is required on `TryGetValue`'s second parameter -- it's how the method hands back the found value alongside its `true`/`false` result.
Knowledge check
Takeaway
Prefer `TryGetValue` over direct dictionary indexing whenever a key's presence isn't guaranteed -- it lets you branch on success safely instead of risking an unhandled exception.
Summary
`List<T>` is C#'s resizable, generic collection; `Dictionary<TKey, TValue>` is its hash map, whose safe lookup pattern is `TryGetValue(key, out value)` rather than direct indexing.
References
Your notes
Notes save automatically.
Finished this lesson?
Mark it complete to track your progress and schedule a future review.
AI tutor
The optional AI tutor isn't enabled in this deployment. All lessons, exercises, quizzes, and search work fully without it.