dictionary iteration
foreach loop
programming tutorial
dictionary traversal
coding guide

Iterating through dictionary with ForEach

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

In C#, iterating a dictionary is usually simple, but there is recurring confusion about foreach versus a hypothetical ForEach method. Dictionary<TKey, TValue> does not expose a built-in .ForEach(...) helper the way List<T> does, so the idiomatic approach is a normal foreach loop over key-value pairs. The important part is understanding what the loop yields, how to access keys and values cleanly, and what changes are safe during enumeration.

Use foreach as the Default Pattern

A dictionary enumerates KeyValuePair<TKey, TValue> entries. That means each loop variable contains both the key and the value:

csharp
1using System;
2using System.Collections.Generic;
3
4var scores = new Dictionary<string, int>
5{
6    ["alice"] = 95,
7    ["bob"] = 88,
8    ["charlie"] = 91
9};
10
11foreach (KeyValuePair<string, int> entry in scores)
12{
13    Console.WriteLine($"{entry.Key}: {entry.Value}");
14}

This is the most direct and readable approach. In business code, it is usually better than forcing a chained LINQ style just to avoid a loop.

Modern C# also supports deconstruction:

csharp
1foreach (var (name, score) in scores)
2{
3    Console.WriteLine($"{name} => {score}");
4}

Use whichever form your codebase finds clearer.

Iterate Keys or Values Only When That Is All You Need

If the loop needs only keys or only values, iterate the dedicated collection instead of ignoring half the pair:

csharp
1foreach (var key in scores.Keys)
2{
3    Console.WriteLine(key);
4}
5
6foreach (var value in scores.Values)
7{
8    Console.WriteLine(value);
9}

This communicates intent better and avoids unused variables. It also makes review easier because the reader can see immediately whether the key, the value, or both are relevant.

Understand Ordering and Determinism

Many developers assume dictionary traversal is naturally sorted. That is not the contract. If you need deterministic output by key, sort explicitly:

csharp
1using System.Linq;
2
3foreach (var pair in scores.OrderBy(p => p.Key))
4{
5    Console.WriteLine($"{pair.Key}: {pair.Value}");
6}

If sorted iteration is your normal access pattern, a SortedDictionary<TKey, TValue> may be a better fit than repeatedly ordering a plain dictionary at call sites.

The key point is to choose a data structure that matches your required semantics instead of depending on incidental iteration behavior.

Do Not Modify Structure While Iterating

You can read dictionary entries safely during enumeration, but adding or removing keys while the loop is active will throw at runtime.

This is unsafe:

csharp
1foreach (var pair in scores)
2{
3    if (pair.Value < 90)
4    {
5        scores.Remove(pair.Key);
6    }
7}

The safe pattern is a two-pass approach:

csharp
1using System.Collections.Generic;
2
3var toRemove = new List<string>();
4
5foreach (var pair in scores)
6{
7    if (pair.Value < 90)
8    {
9        toRemove.Add(pair.Key);
10    }
11}
12
13foreach (var key in toRemove)
14{
15    scores.Remove(key);
16}

The same principle applies if you need to add new entries. Collect the change set first, then apply it after enumeration ends.

Avoid Fake ForEach Patterns

Because Dictionary<TKey, TValue> has no built-in .ForEach, some code converts the dictionary to a list only to call List<T>.ForEach. That usually makes the code worse:

csharp
using System.Linq;

scores.ToList().ForEach(pair => Console.WriteLine($"{pair.Key}: {pair.Value}"));

This allocates an extra list and hides a straightforward loop behind an unnecessary transformation. Unless you have a very specific reason, prefer the ordinary foreach.

If you really want a reusable helper, write an extension method explicitly and use it sparingly:

csharp
1using System;
2using System.Collections.Generic;
3
4public static class DictionaryExtensions
5{
6    public static void ForEach<TKey, TValue>(
7        this IDictionary<TKey, TValue> source,
8        Action<TKey, TValue> action)
9    {
10        foreach (var pair in source)
11        {
12            action(pair.Key, pair.Value);
13        }
14    }
15}

Even then, a plain foreach is often clearer.

Thread Safety Matters

A normal Dictionary<TKey, TValue> is not safe for concurrent mutation. If one thread is iterating while another modifies the dictionary, you can get exceptions or inconsistent behavior.

For shared mutable state, use ConcurrentDictionary<TKey, TValue> and still think carefully about your consistency rules. Safe enumeration at the collection level does not automatically guarantee correct business behavior.

Common Pitfalls

  • Assuming a dictionary has a built-in .ForEach method like List<T>.
  • Modifying keys during foreach enumeration and hitting runtime exceptions.
  • Depending on iteration order when sorted output was actually required.
  • Converting to a list just to call .ForEach, which adds allocation and obscures intent.
  • Ignoring thread-safety concerns when a dictionary is shared across threads.

Summary

  • In C#, the idiomatic way to iterate a dictionary is a normal foreach loop.
  • Dictionary enumeration yields key-value pairs, and deconstruction is available for readability.
  • Iterate Keys or Values directly when only one side is needed.
  • Do structural updates after the loop, not during it.
  • Prefer explicit loops over artificial ForEach wrappers unless a helper clearly improves the codebase.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.