C# foreach Loop
A foreach loop repeats a block of C# code once for each item in a collection. It is the clearest loop when you want the values themselves, not a counter or array index. You will use foreach with arrays, lists, dictionaries, strings, query results, and many other types that can be enumerated.
Overview: How foreach Loops Work
A foreach loop is designed for iteration over a sequence. Instead of saying where to start, when to stop, and how to move to the next index, you say: for each item in this collection, run this body. That makes the intent easy to read and avoids many off-by-one errors that happen with index-based loops.
The collection on the right side of in must be enumerable. In practical terms, that means C# can ask it for an enumerator, then repeatedly ask the enumerator to move to the next item. Arrays, List<T>, Dictionary<TKey, TValue>, string, and many LINQ query results all support this pattern.
The variable declared before in represents the current item for one iteration. Its type is usually the element type of the collection: string for a string[], int for a List<int>, char for a string, and KeyValuePair<TKey, TValue> for a dictionary. You can write the type explicitly or use var when the type is obvious from the collection.
A foreach loop is read-only with respect to the iteration variable. Reassigning the loop variable is not allowed because it would be unclear whether you are trying to replace the item in the collection or only change a local copy. If you need to update elements in an array or list by position, use a for loop with an index.
Under the hood, the compiler translates foreach into enumerator code. For most enumerable objects, it calls GetEnumerator(), then calls MoveNext() until there are no more items. The current item is read from Current. If the enumerator implements IDisposable, the compiler emits cleanup code so the enumerator is disposed even if the loop exits early. Arrays receive special optimized handling, but the result is the same: one iteration per element, in the collection’s enumeration order.
Syntax
string[] names = { "Ava", "Ben" };
foreach (string name in names)
{
Console.WriteLine(name);
}
| Part | Meaning |
|---|---|
foreach |
Starts a loop that visits each item in an enumerable sequence. |
string name |
Declares the loop variable for the current item. Its type must match the item type. |
in |
Separates the loop variable from the source collection. |
names |
The collection or sequence being enumerated. |
{ } |
The body that runs once for each item. |
You can also write foreach (var item in collection). This does not make the item dynamically typed; C# still determines the real type at compile time. Use var when the right side makes the type clear, and use an explicit type when it improves readability.
Examples
Looping Through an Array
using System;
class Program
{
static void Main()
{
string[] languages = { "C#", "Java", "Python" };
foreach (string language in languages)
{
Console.WriteLine($"Learning {language}");
}
}
}
Output:
Learning C#
Learning Java
Learning Python
The array contains three strings, so the loop body runs three times. On each pass, language contains the next array element. There is no index variable to initialize or boundary condition to get wrong.
Calculating a Total from a List
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<decimal> prices = new List<decimal> { 12.50m, 8.25m, 19.99m };
decimal total = 0m;
foreach (decimal price in prices)
{
total += price;
}
Console.WriteLine($"Total: {total:F2}");
}
}
Output:
Total: 40.74
This loop accumulates a value outside the loop. The variable price changes on each iteration, while total keeps its value between iterations. The :F2 format displays the decimal value with exactly two digits after the decimal point.
Iterating Over a Dictionary
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
Dictionary<string, int> inventory = new Dictionary<string, int>
{
{ "notebooks", 12 },
{ "markers", 6 },
{ "erasers", 20 }
};
foreach (KeyValuePair<string, int> item in inventory)
{
Console.WriteLine($"{item.Key}: {item.Value}");
}
}
}
Output:
notebooks: 12
markers: 6
erasers: 20
A dictionary enumerates key-value pairs. Each item has a Key and a Value. Modern dictionaries preserve insertion order during enumeration, but code that depends heavily on ordering should still make that intention explicit, for example by sorting keys before printing.
Using break and continue
using System;
class Program
{
static void Main()
{
int[] scores = { 72, 88, 0, 95, 61 };
int total = 0;
int counted = 0;
foreach (int score in scores)
{
if (score == 0)
{
continue;
}
if (score > 90)
{
Console.WriteLine($"High score found: {score}");
break;
}
total += score;
counted++;
}
Console.WriteLine($"Counted: {counted}");
Console.WriteLine($"Total before high score: {total}");
}
}
Output:
High score found: 95
Counted: 2
Total before high score: 160
continue skips the rest of the current iteration, so the zero score is ignored. break exits the loop completely when the first score greater than 90 is found. As with other loops, these statements affect only the nearest loop.
How foreach Works Step by Step
- The compiler checks that the source expression after
incan be enumerated. - It determines the type of each item and checks that the loop variable can hold that type.
- At runtime, the loop obtains an enumerator for the collection or uses an optimized array path.
- Before each iteration, the enumerator tries to move to the next item.
- If another item exists, the current item is assigned to the loop variable and the body runs.
- If no item remains, the loop ends and execution continues after the closing brace.
- If cleanup is needed, the compiler-generated code disposes the enumerator.
Because foreach asks the collection for items one at a time, it does not copy the whole collection before the loop begins. The exact behavior depends on the collection. For arrays and lists, enumeration walks existing elements. For some LINQ queries, enumeration may calculate each value lazily as the loop requests it.
Most mutable collections do not allow structural changes while they are being enumerated. Adding to or removing from a List<T> inside a foreach loop usually throws an InvalidOperationException. This protects the enumerator from continuing with a collection whose shape changed underneath it.
Common Mistakes
Trying to Change the Loop Variable
foreach (int number in numbers)
{
number = number * 2;
}
This does not compile. The loop variable in a foreach loop is read-only. To replace elements in an array, use an index-based for loop.
using System;
class Program
{
static void Main()
{
int[] numbers = { 1, 2, 3 };
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = numbers[i] * 2;
}
foreach (int number in numbers)
{
Console.WriteLine(number);
}
}
}
Output:
2
4
6
Modifying a List During foreach
List<string> names = new List<string> { "Ava", "Ben", "Chloe" };
foreach (string name in names)
{
if (name.StartsWith("B"))
{
names.Remove(name);
}
}
This compiles, but it changes the list while the list’s enumerator is using it. At runtime, the loop throws an InvalidOperationException. A common fix is to loop backward with a for loop when removing by index.
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> names = new List<string> { "Ava", "Ben", "Chloe" };
for (int i = names.Count - 1; i >= 0; i--)
{
if (names[i].StartsWith("B"))
{
names.RemoveAt(i);
}
}
foreach (string name in names)
{
Console.WriteLine(name);
}
}
}
Output:
Ava
Chloe
Using foreach When You Need the Index
foreach (string name in names)
{
Console.WriteLine($"Item ? is {name}");
}
This loop can print the values, but it has no built-in index variable. If the position is part of the result, use a for loop or maintain a separate counter deliberately.
using System;
class Program
{
static void Main()
{
string[] names = { "Ava", "Ben", "Chloe" };
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine($"Item {i}: {names[i]}");
}
}
}
Output:
Item 0: Ava
Item 1: Ben
Item 2: Chloe
Best Practices
- Use
foreachwhen you want to process every item and do not need an index. - Use
forwhen you need to modify array or list elements by position. - Do not add or remove items from a mutable collection while enumerating it with
foreach. - Choose a meaningful loop variable name such as
price,customer, orscore, not justx. - Use
varwhen the item type is obvious; use an explicit type when it teaches the reader what is being enumerated. - Keep the loop body focused. If the body becomes long, move part of the work into a clearly named method.
- Prefer
foreachover manual indexes for read-only collection traversal because it is less error-prone. - Remember that some sequences are lazy. Enumerating a LINQ query twice may repeat the query work twice.
Practice Exercises
- Create an array of five city names and use
foreachto print each city on its own line. - Create a
List<int>of temperatures and useforeachto count how many are below freezing. - Create a
Dictionary<string, decimal>of product names and prices, then useforeachto print only products that cost at least10m.
Summary
- A
foreachloop runs once for each item in an enumerable collection. - It is ideal for reading and processing values without managing indexes manually.
- The compiler uses the enumerator pattern behind the scenes, with optimized handling for arrays.
- The loop variable is read-only, so use
forwhen you need to replace elements by index. - Do not structurally modify mutable collections during enumeration.
breakexits the loop, andcontinueskips to the next item.
