C# Dictionary Key-Value Iteration: Methods and Pitfalls
c# dictionary key value iteration: Learn how to iterate over C# Dictionary key-value pairs using foreach, LINQ, and other approaches, with performance and safety consi...
c# dictionary key value iteration requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
When you need to iterate over the key-value pairs in a C# Dictionary<TKey,TValue>, the most common approach is a foreach loop. The Dictionary class implements IEnumerable<KeyValuePair<TKey,TValue>>, so each iteration yields a KeyValuePair structure containing the current Key and Value. This is the foundation for all other iteration techniques, and understanding it directly informs how you handle ordering, modification, and performance.
Using foreach to Enumerate Entries
The simplest way to perform c# dictionary key value iteration is with a foreach loop over the dictionary itself. The loop variable is a KeyValuePair<TKey,TValue> instance, giving you direct access to both the key and the value without an extra lookup.
var settings = new Dictionary<string, string> { ["host"] = "localhost", ["port"] = "8080", ["timeout"] = "30" }; foreach (KeyValuePair<string, string> entry in settings) { Console.WriteLine($"{entry.Key}: {entry.Value}"); }
This works because Dictionary<TKey,TValue> implements IEnumerable<KeyValuePair<TKey,TValue>>. The compiler translates the foreach into a call to GetEnumerator(), which returns a struct-based enumerator that avoids boxing and is generally efficient. The order of iteration is not guaranteed; it follows the internal bucket layout, which can change when items are added or removed. If you rely on insertion order, use an ordered collection such as SortedDictionary or a list of pairs.
Working with KeyValuePair Directly
Each entry in a dictionary is a KeyValuePair<TKey,TValue> struct. Its Key and Value properties are read-only. You cannot modify the dictionary by assigning to these properties; the struct is a snapshot of the entry at the moment it is enumerated. If you need to update the value for a key, use the indexer or the TryGetValue method instead.
foreach (var entry in inventory) { // This does NOT update the dictionary. // entry.Value = entry.Value * 2; // Compile error: property is read-only }
To update values during iteration, you must either collect the keys first and then modify, or use a different approach such as iterating over a copy of the keys. The KeyValuePair struct is useful when you need to pass both key and value to a method or store them in another collection.
Using LINQ to Transform or Filter Entries
LINQ provides a fluent way to work with dictionary entries. You can use Where, Select, ToDictionary, and other operators to filter or project the key-value pairs. This is particularly useful when you need to create a new dictionary or a list of transformed values.
var filtered = settings .Where(entry => entry.Value.Length > 3) .ToDictionary(entry => entry.Key, entry => entry.Value); var keysOnly = settings.Select(entry => entry.Key).ToList();
LINQ operations return lazy sequences when you use Where or Select. If you iterate the result multiple times, the dictionary is enumerated each time. Materialize the result with ToList() or ToDictionary() when you need a snapshot or plan to iterate repeatedly. This avoids re-enumerating the dictionary and potential side effects if the dictionary changes between iterations.
Modifying a Dictionary While Iterating
Attempting to add or remove entries from a dictionary inside a foreach loop throws an InvalidOperationException with a message like "Collection was modified; enumeration operation may not execute." This happens because the dictionary tracks a version number, and the enumerator checks it on each MoveNext call. The exception protects you from undefined behavior that could cause infinite loops or missed entries.
// This throws InvalidOperationException foreach (var entry in settings) { if (entry.Key == "host") { settings.Remove(entry.Key); // Throws } }
To safely modify the dictionary, iterate over a copy of the keys or entries. The most common pattern is to collect the keys that need to be removed first, then remove them after the loop.
var keysToRemove = settings.Keys .Where(key => key.StartsWith("temp")) .ToList(); foreach (var key in keysToRemove) { settings.Remove(key); }
Alternatively, you can use ToList() on the dictionary itself to create a snapshot of the entries, then iterate that list and modify the original dictionary.
Performance Considerations
Iterating a dictionary with foreach is generally fast because the enumerator is a struct and does not allocate on the heap. However, the exact cost depends on the number of entries and the work done inside the loop. Accessing entry.Key and entry.Value is a direct field read, not a lookup, so it is cheaper than using the indexer with dictionary[key] inside the loop.
If you only need the values, you can iterate dictionary.Values directly, which avoids the overhead of constructing KeyValuePair objects (though the enumerator still yields each value). Similarly, iterating dictionary.Keys is efficient when you only need keys. These properties return a KeyValuePair-free view, but they still enumerate the dictionary's internal structure.
LINQ operators add a small overhead due to delegate invocations and iterator state machines. For most applications this is negligible, but in tight loops with millions of entries, a plain foreach will outperform a LINQ query that does the same work. If you need to transform every entry, consider using a for loop over the entries after materializing them into an array or list, though this adds memory overhead.
Another performance factor is the dictionary's internal layout. The iteration order is not deterministic, and it can change when the dictionary is resized. If you need a stable order, sort the keys or entries before iterating. Sorting adds O(n log n) complexity, so only do it when order matters.
Choosing the Right Iteration Approach
The method you choose depends on what you need to accomplish. For simple enumeration, foreach is the clearest and most efficient. If you need to filter or project, LINQ offers concise syntax, but be mindful of deferred execution. When modifying the dictionary, always iterate over a snapshot to avoid exceptions. If you need to update values, consider using the indexer with the key rather than trying to change the KeyValuePair.
| Scenario | Recommended Approach |
|---|---|
| Read all key-value pairs | foreach over dictionary |
| Read only keys | foreach over Keys |
| Read only values | foreach over Values |
| Filter and create new dictionary | LINQ Where + ToDictionary |
| Modify (remove) during iteration | Collect keys first, then remove |
| Update values in place | Use indexer with key inside loop |
These choices balance readability, safety, and performance. In most production code, the simplest approach yields the fewest surprises. Reserve LINQ for cases where the transformation is complex or you need to chain multiple operations.
Handling Order and Dependencies
Because Dictionary<TKey,TValue> does not guarantee iteration order, you should not write code that depends on the sequence of entries. If your logic requires a specific order, sort the entries before processing. For example, to iterate in key order, you can use OrderBy from LINQ or copy the keys to an array and sort it.
foreach (var key in settings.Keys.OrderBy(k => k)) { Console.WriteLine($"{key}: {settings[key]}"); }
This performs a sort and then a lookup per key, which is O(n log n) plus O(n) lookups. If the dictionary is large and you need sorted iteration frequently, consider using SortedDictionary<TKey,TValue> instead, which maintains order at the cost of slower insertions and removals.
Another dependency is thread safety. The Dictionary class is not thread-safe for concurrent reads and writes. If you iterate a dictionary while another thread modifies it, you can get an InvalidOperationException or inconsistent data. Use a ConcurrentDictionary when you need concurrent access, and be aware that its enumerator provides a snapshot of the collection at the time of enumeration, which may not reflect subsequent changes.
Advanced: Iterating with Span and Low-Allocation Patterns
In high-performance scenarios, you might want to avoid any allocation from LINQ or boxing. The foreach loop over a dictionary does not allocate, but the KeyValuePair struct is copied on each iteration. This is a value type, so the copy is cheap. If you need to pass the pair to a method that accepts in parameters, you can use foreach (in var entry in dictionary) in C# 7.2 or later to avoid copying the struct.
foreach (in KeyValuePair<string, int> entry in counts) { Process(in entry); }
This is a micro-optimization that matters only in extremely tight loops with large structs. For most applications, the standard foreach is sufficient. If you are building a library that exposes dictionary iteration, consider returning IEnumerable<KeyValuePair<TKey,TValue>> to allow callers to use foreach without extra allocations.
When you need to iterate over a dictionary's entries and also access the index (for example, to compare adjacent entries), you can materialize the entries into an array using ToArray() and then use a for loop. This adds memory overhead but gives you indexed access. Only do this if you genuinely need the index and cannot restructure the logic.