Last Updated: May 17, 2026
The foreach loop walks every item in a collection, one at a time, without making you think about indices or bounds checks. When you have a cart, a wishlist, or a catalog and you just want to look at each thing inside it, this is the loop you reach for. Unlike for and while, which are built around a counter, foreach is built around the items themselves, and it works on more than just arrays.
The syntax is short and reads almost like a sentence: for each item in the collection, do something.
Three things are happening here. cart is the collection. item is the iteration variable, a fresh local name that holds one element per pass. The keyword in ties the two together. On the first pass, item is "Wireless Mouse". On the second, it's "USB Cable". On the third, "HDMI Adapter". After that the loop ends because there's nothing left.
Compare the same loop written with for:
Both print the same output. The foreach version doesn't mention an index, doesn't compare against cart.Length, and doesn't need an increment. There's less to read and less to get wrong.
A collection works with foreach if it exposes a GetEnumerator() method that returns something with two members: a Current property and a MoveNext() method. C# doesn't actually require the collection to implement IEnumerable or IEnumerable<T>. It only requires the shape. This pattern is sometimes called duck typing: if it looks like an enumerable and acts like an enumerable, foreach is happy.
In practice, every common collection in .NET supports foreach:
string[], int[], Product[]List<T> and LinkedList<T>Dictionary<TKey, TValue>, HashSet<T>, SortedSet<T>Queue<T> and Stack<T>string (each item is a char)IEnumerable<T>Here's the same idea applied to a List<T> of decimals representing line-item prices:
And on a string, since a string is a sequence of char:
Under the hood, foreach is rewritten by the compiler into a call to GetEnumerator() followed by a loop on MoveNext() and Current. You almost never write that by hand, but knowing the shape is what lets foreach work on so many different types.
The diagram shows the cycle every foreach performs. The runtime asks the enumerator "is there another item?" by calling MoveNext(). If yes, it reads Current into the iteration variable and runs the body. If no, the loop exits. You don't write any of this, but you'll see the shape again later when you build your own iterators with yield.
Both forms are valid. The choice is about clarity, not correctness.
Use var when the element type is obvious from the collection on the same line. Use the explicit type when the collection comes from far away, or when the type isn't immediately clear from context, or when you specifically want the reader to think about the type. Both compile to the same code.
One small thing worth flagging: the iteration variable's type doesn't have to match the collection's element type exactly. If the elements are a derived type, you can declare the iteration variable as the base type:
That compiles because every string is also an object. The opposite direction (declaring a more specific type than the collection holds) requires a cast and can fail at runtime.
A Dictionary<TKey, TValue> stores key-value pairs. When you foreach over a dictionary, each item is a KeyValuePair<TKey, TValue> with a Key and a Value property.
If you only care about the keys or only the values, the dictionary exposes those as their own enumerable properties:
Since C# 7.3, KeyValuePair<TKey, TValue> supports deconstruction, which lets you split the pair into two named variables on the same line. This makes the loop body shorter and the intent clearer:
(var productName, var count) is the deconstruction syntax. The compiler matches the two names to the Key and Value of each pair. You can use this whenever the element type has a Deconstruct method, which includes tuples and records as well.
A note on dictionary order: a regular Dictionary<TKey, TValue> does not guarantee any specific iteration order. In current .NET versions it tends to come out in insertion order for many inputs, but you shouldn't rely on it. If you need a stable order, sort the keys explicitly or use SortedDictionary<TKey, TValue>.
You can read the iteration variable inside the loop body, but you can't assign to it. The compiler enforces this.
What's wrong with this code?
The compiler reports CS1656: Cannot assign to 'price' because it is a 'foreach iteration variable'. The iteration variable is a fresh local on every pass, and the language treats it as if it were readonly so you don't accidentally mistake it for a way to update the collection.
Fix: Use a separate local variable to hold the computed value:
If you need to actually update the elements inside the collection, foreach isn't the right tool. Use a for loop indexed by position so you can assign back into the collection at that index:
That's one of the cases where for still wins. We'll come back to this question more carefully in a moment.
This one is a runtime error rather than a compile error. The language can't catch every shape of "I changed the collection while looping over it," so the enumerator checks at runtime and throws when it sees a change.
What's wrong with this code?
The program crashes with System.InvalidOperationException: Collection was modified; enumeration operation may not execute. The enumerator internally tracks a version number on the list. Adding, removing, or clearing items bumps that number. The next call to MoveNext() notices the mismatch and throws.
Cost: Modifying a collection inside foreach throws InvalidOperationException at runtime. Build a list of changes first and apply them after the loop, or iterate with a for loop running backwards so removed indices don't shift the items still ahead of you.
Fix (option 1): Decide what to remove, then remove it after the loop ends.
Fix (option 2): Use a for loop iterating from the end. Removing an item at index i only affects indices after i, so going backwards keeps the indices you haven't visited yet stable.
Fix (option 3): Use List<T>.RemoveAll, which is built for this case.
Same output. RemoveAll knows how to walk the list once and shift items in place, and it doesn't trip the enumerator because it doesn't use one.
A small subtlety: changing a value inside the iterated object (not the collection itself) is fine. If the collection is List<Product> and you mutate a property on each Product you visit, the enumerator doesn't notice or care. The version check is only triggered by structural changes to the collection (add, remove, clear, resize).
The two loops solve different problems. for is built around an index. foreach is built around an item. Most of the time foreach is the right default, but for has a few clear advantages that haven't gone away.
| Situation | Prefer | Why |
|---|---|---|
| Walk every item in a collection | foreach | Cleaner, no off-by-one risk |
| Need the index of each item | for | foreach doesn't expose one |
| Step through every other element | for | foreach always advances by one |
| Iterate from the end backwards | for | foreach only goes forwards |
| Remove items during iteration | for (reverse) or RemoveAll | foreach throws on modification |
Iterate over an IEnumerable<T> you only get once | foreach | The standard pattern; for doesn't work without a count |
| Update elements at known positions | for | foreach's iteration variable is read-only |
A concrete example where foreach would feel awkward: printing a numbered list of cart items. The number is the position, which foreach doesn't give you directly.
You can fake it inside a foreach with a manual counter, but at that point you've reinvented for:
There's also LINQ's Select with an index, which is the idiomatic answer once you reach the LINQ chapter:
For now, prefer for when the index matters. Prefer foreach when it doesn't. That single rule covers most code.
A small program that prints a cart receipt by iterating items, then iterating a grouped view of categories. This is the kind of code where foreach shines: you have a collection, you want to look at every item, and you don't care about positions.
Three foreach loops, each doing one thing. The first walks the cart and accumulates a total. The second walks the cart again to group items by category into a dictionary of lists. The third is a nested foreach: outer loop over the dictionary's (category, names) pairs, inner loop over each category's list. Nesting foreach inside foreach is fine and is how you iterate any two-level collection (a dictionary of lists, a list of lists, and so on).
For most code this is a detail you can ignore. But it shows up in profilers often enough that it's worth one short section.
When you foreach over an array like string[], the C# compiler doesn't actually call GetEnumerator(). It rewrites the loop into the equivalent index-based for loop because arrays have a known length and indexer. No enumerator object gets allocated. The same holds for List<T> when the iteration variable is declared as List<T>'s specific element type, because List<T> exposes a struct-based enumerator that the compiler can use without boxing.
When you foreach over something typed as IEnumerable<T>, the compiler doesn't know which concrete collection it is, so it calls GetEnumerator() through the interface. That call returns a fresh enumerator object allocated on the heap. One allocation per loop. In ordinary code this is invisible. In a tight hot loop running millions of times per second, it can show up as garbage collection pressure.
Cost: foreach over an IEnumerable<T> allocates one enumerator object per loop. For most code this is fine. In a hot loop, prefer a concrete collection type (List<T>, array) so the compiler can avoid the allocation, or switch to a for loop indexed by position.
This isn't a reason to avoid foreach. It's a reason to know that "free abstraction" isn't quite true, and that when performance matters, the concrete type of the collection variable can matter too.
A few patterns that trip up newcomers, gathered in one place.
Trying to assign to the iteration variable. CS1656. The iteration variable is read-only. Use a separate local inside the body, or switch to for if you actually need to write back into the collection.
Removing items mid-iteration. InvalidOperationException. Collect changes first and apply them after the loop, or use RemoveAll, or iterate by index in reverse.
Forgetting that the iteration variable is a copy for value types. Mutating a property on a struct that you got from a foreach doesn't affect the original in the collection, because the iteration variable holds a copy. This rarely matters for built-in types, but it matters for custom mutable structs.
Expecting a specific iteration order from a `HashSet<T>` or `Dictionary<TKey, TValue>`. Neither type guarantees order. If you need order, sort the items first or pick an ordered collection (SortedSet<T>, SortedDictionary<TKey, TValue>, or a List<T> you've sorted explicitly).
Iterating an empty collection and assuming the loop runs at least once. It doesn't. If the collection has zero items, the body never executes. Initialize accumulators (totals, counters) outside the loop so they have valid values when the loop is skipped entirely.
foreach (var item in collection) walks every element of a collection in order, without indices or bounds checks.foreach if it exposes a GetEnumerator() method that returns something with a Current property and a MoveNext() method. Arrays, List<T>, Dictionary<TKey, TValue>, HashSet<T>, strings, and LINQ results all qualify.Dictionary<TKey, TValue> yields KeyValuePair<TKey, TValue> entries. Since C# 7.3 you can deconstruct each pair directly: foreach (var (key, value) in dict).CS1656).foreach throws InvalidOperationException at runtime. Use RemoveAll, a reverse for loop, or a side list of changes.foreach when you only need each item. Prefer for when you need the index, a non-unit step, reverse order, or in-place updates.foreach over an array or a concrete List<T> doesn't allocate an enumerator object. foreach over an IEnumerable<T> does.