Question
In C#, I have seen several different ways to iterate over a dictionary. Is there a standard or recommended way to do it?
For example, given a dictionary like this:
var scores = new Dictionary<string, int>
{
{ "Alice", 95 },
{ "Bob", 87 },
{ "Charlie", 91 }
};
What is the usual way to loop through its contents, and when should I iterate over key-value pairs instead of only keys or only values?
Short Answer
By the end of this page, you will understand the standard way to iterate over a Dictionary<TKey, TValue> in C#, how to access keys and values, when to use foreach with KeyValuePair, and which common patterns developers use in real projects.
Concept
A dictionary in C# stores data as key-value pairs. Each key is unique, and each key maps to one value.
When you iterate over a dictionary, the most common goal is one of these:
- read both the key and the value
- read only the keys
- read only the values
The standard way to iterate over a dictionary is with foreach. A Dictionary<TKey, TValue> is enumerable, so you can loop through it directly.
When you do that, each item is a KeyValuePair<TKey, TValue>. That means each loop iteration gives you:
item.Keyitem.Value
Example:
foreach (KeyValuePair<string, int> item in scores)
{
Console.WriteLine($"{item.Key}: {item.Value}");
}
In modern C#, var is also common:
foreach (var item in scores)
{
Console.WriteLine($"{item.Key}: {item.Value}");
}
This matters because dictionaries are used everywhere in real applications:
- caching values by ID
- storing configuration settings
- counting occurrences of items
- looking up data quickly by key
- processing API response fields
If you need both parts, iterate over the dictionary itself. If you only need one part, use .Keys or .Values for clarity.
Mental Model
Think of a dictionary like a set of labeled drawers.
- The key is the label on the drawer.
- The value is what is stored inside.
When you iterate over the whole dictionary, you walk past each drawer and see both the label and the contents.
When you iterate over .Keys, you only read the labels.
When you iterate over .Values, you only inspect the contents.
So the question is simple: what information do you need while looping?
- Need both label and content? Loop through the dictionary.
- Need only labels? Loop through
Keys. - Need only contents? Loop through
Values.
That is the mental shortcut most developers use.
Syntax and Examples
Standard way: iterate over key-value pairs
var scores = new Dictionary<string, int>
{
{ "Alice", 95 },
{ "Bob", 87 },
{ "Charlie", 91 }
};
foreach (var pair in scores)
{
Console.WriteLine($"{pair.Key} => {pair.Value}");
}
This is the most common and recommended approach when you need both the key and the value.
Iterate over only keys
foreach (var key in scores.Keys)
{
Console.WriteLine(key);
}
Use this when only the keys matter.
Iterate over only values
foreach (var value in scores.Values)
{
Console.WriteLine(value);
}
Use this when only the values matter.
Deconstruction syntax
In modern C#, you can deconstruct key-value pairs:
foreach (var (name, score) in scores)
{
Console.WriteLine($"{name}: {score}");
}
This is often easier to read.
Example: filtering while iterating
foreach (var (name, score) in scores)
{
if (score >= 90)
{
Console.WriteLine($"High score: {name}");
}
}
This loops through each entry and prints only students with scores of 90 or more.
Step by Step Execution
Consider this code:
var scores = new Dictionary<string, int>
{
{ "Alice", 95 },
{ "Bob", 87 }
};
foreach (var pair in scores)
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}
Step by step:
- A dictionary named
scoresis created. - It contains two entries:
- key
"Alice"with value95 - key
"Bob"with value87
- key
- The
foreachloop starts. - On the first iteration,
pairrepresents one key-value pair, for example:pair.Keyis"Alice"pair.Valueis95
- The program prints:
Alice: 95
- On the second iteration,
pairrepresents the next entry:pair.Keyis"Bob"pair.Valueis87
- The program prints:
Bob: 87
- The loop ends after all entries are visited.
Important note about order
A dictionary is optimized for lookup by key, not for preserving insertion order as the main idea of the type. In practice, you should not write logic that depends on a specific iteration order unless your chosen collection type guarantees the behavior you need.
Real World Use Cases
Configuration settings
var settings = new Dictionary<string, string>
{
{ "Theme", "Dark" },
{ "Language", "en-US" },
{ "Region", "US" }
};
foreach (var (key, value) in settings)
{
Console.WriteLine($"{key} = {value}");
}
Useful for printing, validating, or exporting app settings.
Counting occurrences
var wordCounts = new Dictionary<string, int>
{
{ "apple", 3 },
{ "banana", 5 }
};
foreach (var (word, count) in wordCounts)
{
Console.WriteLine($"{word} appears {count} times");
}
Common in text analysis and reporting.
API or JSON-like field processing
Some applications map field names to values for dynamic processing.
var fields = new Dictionary<string, string>
{
{ "firstName", "Sam" },
{ "lastName", "Lee" }
};
foreach (var (fieldName, fieldValue) in fields)
{
Console.WriteLine($"Processing {fieldName}: {fieldValue}");
}
Caching
var cache = new Dictionary<int, string>
{
{ 101, "Product A" },
{ 102, "Product B" }
};
foreach (var (id, productName) in cache)
{
Console.WriteLine($"Cached item {id}: {productName}");
}
Used when reviewing or logging cache contents.
Real Codebase Usage
In real codebases, developers usually choose the loop style based on what they need.
Common pattern: iterate over the whole dictionary
Use this when you need both key and value.
foreach (var (userId, userName) in users)
{
logger.LogInformation($"User {userId}: {userName}");
}
Common pattern: validation
foreach (var (field, value) in formData)
{
if (string.IsNullOrWhiteSpace(value))
{
Console.WriteLine($"Missing value for {field}");
}
}
This is common in request validation and data cleaning.
Common pattern: guard clause before lookup or processing
if (scores.Count == 0)
{
return;
}
foreach (var (name, score) in scores)
{
Console.WriteLine($"{name}: {score}");
}
Common pattern: use TryGetValue instead of iterating for one key
If you need just one value, do not loop through the whole dictionary.
if (scores.TryGetValue("Alice", out int score))
{
Console.WriteLine(score);
}
Common pattern: transform with LINQ when needed
var topStudents = scores
.Where(pair => pair.Value >= 90)
.Select(pair => pair.Key)
.ToList();
Developers often combine dictionary iteration with filtering, projection, and validation.
Avoid modifying during enumeration
A common real-world rule is: do not add or remove dictionary items inside a foreach over that same dictionary.
Common Mistakes
1. Iterating over keys when you really need both key and value
Broken or less clear approach:
foreach (var key in scores.Keys)
{
Console.WriteLine($"{key}: {scores[key]}");
}
This works, but if you need both key and value, iterating over the dictionary directly is clearer.
Better:
foreach (var pair in scores)
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}
2. Expecting a guaranteed order
Beginners sometimes assume the items will always come out in a specific order.
foreach (var pair in scores)
{
Console.WriteLine(pair.Key);
}
Do not build logic that depends on order unless you use a collection type intended for ordered behavior.
3. Modifying the dictionary during foreach
Broken example:
foreach (var pair in scores)
{
if (pair.Value < 90)
{
scores.Remove(pair.Key);
}
}
This can throw an exception.
Safer approach:
var keysToRemove = new List<string>();
foreach (var pair in scores)
{
if (pair.Value < 90)
{
keysToRemove.Add(pair.Key);
}
}
foreach (var key in keysToRemove)
{
scores.Remove(key);
}
4. Using iteration for lookup
Broken idea:
foreach (var pair in scores)
{
if (pair.Key == "Alice")
{
Console.WriteLine(pair.Value);
}
}
Better:
if (scores.TryGetValue("Alice", out int score))
{
Console.WriteLine(score);
}
5. Confusing KeyValuePair with just a value
Broken example:
foreach (var item in scores)
{
Console.WriteLine(item);
}
This prints the pair object representation, which is usually not what beginners expect.
Better:
foreach (var item in scores)
{
Console.WriteLine($"{item.Key}: {item.Value}");
}
Comparisons
| Approach | Best when | Example | Notes |
|---|---|---|---|
foreach (var pair in dictionary) | You need both key and value | pair.Key, pair.Value | Standard and most common |
foreach (var key in dictionary.Keys) | You only need keys | key | Clear and direct |
foreach (var value in dictionary.Values) | You only need values | value | Best when keys are irrelevant |
foreach (var (key, value) in dictionary) | You need both, with cleaner syntax | key, value | Nice modern C# style |
for loop | Rarely used with dictionaries | Not typical | Dictionaries are not index-based |
Dictionary iteration vs lookup
| Task | Better choice |
|---|---|
| Process every entry | Iterate with foreach |
| Find one value by key | TryGetValue |
| Check if a key exists | ContainsKey or TryGetValue |
| Use only values | dictionary.Values |
foreach vs for
| Feature | foreach | for |
|---|---|---|
| Works naturally with dictionaries | Yes | Not really |
| Uses indexes | No | Yes |
| Best for collections of entries | Yes | No |
| Beginner readability | High | Lower for dictionaries |
Cheat Sheet
Quick reference
Iterate over key-value pairs
foreach (var pair in dictionary)
{
Console.WriteLine(pair.Key);
Console.WriteLine(pair.Value);
}
Iterate over keys only
foreach (var key in dictionary.Keys)
{
Console.WriteLine(key);
}
Iterate over values only
foreach (var value in dictionary.Values)
{
Console.WriteLine(value);
}
Deconstruct pairs
foreach (var (key, value) in dictionary)
{
Console.WriteLine($"{key}: {value}");
}
Look up one key
if (dictionary.TryGetValue("someKey", out var value))
{
Console.WriteLine(value);
}
Rules of thumb
- Use
foreachas the standard way to iterate a dictionary. - Loop over the dictionary itself when you need both key and value.
- Use
.Keysor.Valueswhen you only need one side. - Do not use a
forloop unless you have a special reason. - Do not modify the dictionary while iterating with
foreach. - Do not iterate just to find one known key.
Edge case reminders
- Dictionary iteration order should not be relied on unless the collection type guarantees the behavior you need.
- Keys are unique.
- Values do not have to be unique.
FAQ
Is foreach the standard way to iterate over a dictionary in C#?
Yes. foreach is the normal and recommended way to iterate over a Dictionary<TKey, TValue>.
What type do I get when I loop over a dictionary?
Each item is a KeyValuePair<TKey, TValue>, so you can access .Key and .Value.
Should I loop over Keys and then use dictionary[key]?
Only if you truly only need keys. If you need both key and value, iterating over the dictionary directly is usually clearer.
Can I use a for loop with a dictionary?
Not naturally. Dictionaries are not index-based collections, so foreach is the better fit.
Can I change the dictionary while looping through it?
Not safely with a normal foreach. Adding or removing entries during enumeration can cause an exception.
How do I get just one value from a dictionary?
Use TryGetValue instead of iterating through every item.
Is deconstruction a good way to iterate?
Yes, if your C# version supports it. foreach (var (key, value) in dictionary) is often clean and readable.
Mini Project
Description
Build a simple student score reporter using a C# dictionary. This project demonstrates the standard way to iterate over dictionary entries, print formatted output, and apply a small condition while looping.
It is useful because dictionaries are commonly used to map names, IDs, or codes to values in real applications.
Goal
Create a program that stores student scores in a dictionary, prints every student and score, and highlights students with scores of 90 or higher.
Requirements
- Create a
Dictionary<string, int>with at least four student scores. - Iterate over the dictionary using
foreach. - Print each student's name and score.
- Print a second message for students whose score is 90 or higher.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Access Modifiers and static: public, private, protected, and Defaults
Learn how C# public, private, protected, and default access control visibility, and how static differs from instance members.