intermediate18 min

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

C#Not executed
This lab does not run in your browser or on VisaSparkSchools's servers. Read the code, fill in the missing piece, then reveal the completed code and its expected output.

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

Knowledge check

1. What happens when you index a `Dictionary<TKey, TValue>` directly with a key that doesn't exist?
2. What does `TryGetValue` return when the key does exist?
3. What does the `<T>` in `List<T>` indicate?

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.