foreach runs its body once for every element of a collection, in order, with no index to manage:
Output:
Welcome, Ava
Welcome, Noah
Welcome, Mia
Total: 255
[C][#][7]
The loop works the same on an array, a List<T>, a string (element type char), a HashSet<T>, a LINQ query or any other sequence. The declared type can be var, which is common when the element type is long: foreach (var order in pendingOrders).
What foreach Does Behind the Scenes
foreach asks the collection for an enumerator and walks it. For a List<int>, the compiler turns the loop into roughly this:
List<int>.Enumerator e = scores.GetEnumerator();
try
{
while (e.MoveNext())
{
int score = e.Current;
// loop body
}
}
finally
{
e.Dispose();
}
Three consequences follow. Any type with a public GetEnumerator() method works, which is normally provided by implementing IEnumerable<T>. The enumerator is disposed even when the body throws or breaks. And the element variable is a fresh copy of e.Current on every pass, which is why assigning to it cannot change the collection.
A type without GetEnumerator cannot be used:
error CS1579: foreach statement cannot operate on variables of type 'Order' because 'Order' does not contain a public instance or extension definition for 'GetEnumerator'
Implement IEnumerable<T> on the type, or loop over the collection it contains (order.Lines instead of order). You can write your own sequences with yield return, covered on the IEnumerable and yield page.
Looping Over a Dictionary
A dictionary's elements are KeyValuePair<TKey, TValue> values with Key and Value properties:
Output:
apples: 12
pears: 0
kiwis: 30
<apples><pears><kiwis>
Units in stock: 42
30 kiwis
12 apples
0 pears
A Dictionary does not promise any enumeration order. In practice it follows insertion order until you remove entries, but code that depends on order should sort explicitly, as the last loop does with OrderByDescending, or use SortedDictionary.
On .NET Core 2.0 and later (and every modern .NET), KeyValuePair has a Deconstruct method, so the pair can be split into two variables directly in the loop header:
// modern .NET: KeyValuePair deconstruction
foreach (var (fruit, count) in stock)
{
Console.WriteLine($"{fruit}: {count}");
}
This is the shortest form and the one you will see in current code. It does not compile on .NET Framework, where KeyValuePair has no Deconstruct; use item.Key and item.Value there.
Getting the Index
foreach has no index of its own. The two usual ways to get one are a counter you maintain, or LINQ's Select overload that passes the index along with each element:
Output:
1. Kenji
2. Sofia
3. Omar
index 0: Kenji
index 1: Sofia
index 2: Omar
The counter is the cheapest and clearest. If you find yourself using the index to read podium[i - 1] or to write podium[i] = ..., switch to a for loop, which is built for exactly that.
The Loop Variable Is Read-Only
You cannot assign to the iteration variable:
foreach (string name in names)
{
name = name.Trim();
// error CS1656: Cannot assign to 'name' because it is a 'foreach iteration variable'
}
Even if it were allowed, it would only change a local copy. To transform every element, build a new sequence (names.Select(n => n.Trim()).ToArray()) or use a for loop that writes names[i] = names[i].Trim().
What you can do depends on whether the element is a class or a struct. For a class, the variable holds a reference, so changing a property changes the object in the collection:
Output:
Order 1: shipped
Order 2: shipped
If Order were a struct, the same assignment fails with CS1654 (Cannot modify members of 'order' because it is a 'foreach iteration variable'), because the variable is a copy of the value, not a reference to it.
Modifying the Collection: InvalidOperationException
Adding or removing elements of a List or Dictionary while a foreach walks it breaks the enumerator. The next MoveNext throws InvalidOperationException with the message "Collection was modified; enumeration operation may not execute.":
Output:
InvalidOperationException: collection was modified
milk, bread
milk, bread
The fixes, from simplest to most flexible:
RemoveAll(predicate)on aList<T>removes every match in one pass.- Loop over a copy with
ToList()orToArray(), then modify the original freely. - Collect first, apply after: gather keys to delete in a separate list during the loop, then remove them afterwards. This is the usual pattern for a
Dictionary. - A backwards
forloop withRemoveAt(i).
Dictionary has one exception worth knowing. Since .NET Core 3.0, overwriting the value of an existing key (stock[key] = 0) or removing entries during a foreach over it no longer throws, while adding a new key still does. On .NET Framework all three throw, so collecting the keys first is the version that works everywhere.
break, continue and Null Collections
break and continue behave as in every other loop:
Output:
reading 21
reading 23
no tags, no crash
Looping over a null collection throws NullReferenceException when GetEnumerator is called. ?? Enumerable.Empty<T>() turns a possibly-null sequence into an empty one; better still, return empty collections instead of null from your own methods.
foreach Versus List.ForEach
List<T> has a ForEach(Action<T>) method: names.ForEach(n => Console.WriteLine(n));. It is not the same as the loop. Its body is a lambda, so break, continue and yield are unavailable and return only ends the current element's call. It exists only on List<T>, not on arrays or other sequences. Prefer the foreach statement; use ForEach only for a one-line action you already have as a method.
Frequently Asked Questions
How do I loop through a Dictionary with foreach in C#?
Each element is a KeyValuePair<TKey, TValue>: foreach (var pair in prices) Console.WriteLine($"{pair.Key}: {pair.Value}");. On .NET Core 2.0 and later you can deconstruct it: foreach (var (name, price) in prices). To loop over only the keys or values, use prices.Keys or prices.Values.
How do I get the index in a C# foreach loop?
foreach has no built-in index. Keep a counter (int i = 0; before the loop, i++ at the end of the body), or project each element with its index using LINQ: foreach (var item in names.Select((name, index) => new { name, index })). If you need the index to write back or compare neighbors, a for loop is the better fit.
What does "Collection was modified; enumeration operation may not execute" mean?
You added or removed items in a List, Dictionary or other collection while a foreach was enumerating it. The enumerator detects the change and throws InvalidOperationException on the next step. Loop over a copy (foreach (var x in list.ToList())), collect the changes and apply them after the loop, use list.RemoveAll(...), or use a backwards for loop.
Why can't I assign to the foreach variable in C#?
The iteration variable is read-only: name = name.Trim(); inside foreach (string name in names) is error CS1656. Assigning it would not change the collection anyway. To replace elements, use a for loop with an index, or build a new collection with Select. Changing a property of a class object (order.Status = ...) is allowed.
Can you break out of a foreach loop in C#?
Yes. break ends the loop immediately and continue skips to the next element, exactly as in for and while. return leaves the whole method. The List<T>.ForEach method is different: its body is a lambda, so break and continue are not available there.