Syntax
foreach (Type item in collection) {\n // code\n}Examples
Basic foreach Usage
Iterating over different built-in collection types with the same syntax.
List<string> names = new List<string> { "Fola", "Zain", "Jamal" };
foreach (string name in names)
{
Console.WriteLine(name);
}
int[] numbers = { 1, 2, 3 };
foreach (int n in numbers)
{
Console.WriteLine(n * n);
}foreach with var
Using var lets the compiler infer the element type, useful when working with complex generic types.
Dictionary<string, int> scores = new Dictionary<string, int>
{
["Alice"] = 85,
["Bob"] = 92
};
foreach (var entry in scores) // type inferred as KeyValuePair<string, int>
{
Console.WriteLine($"{entry.Key}: {entry.Value}");
}Implementing IEnumerable in a Custom Class
Making a custom class support foreach by implementing IEnumerable<T>, often with a yield return generator method.
public class NumberRange : IEnumerable<int>
{
private int _start, _end;
public NumberRange(int start, int end) { _start = start; _end = end; }
public IEnumerator<int> GetEnumerator()
{
for (int i = _start; i <= _end; i++)
yield return i;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
=> GetEnumerator();
}
foreach (int n in new NumberRange(1, 5))
{
Console.WriteLine(n); // 1, 2, 3, 4, 5
}Best practices
- Use foreach by default for reading through a collection - it is safer and more readable than a manual indexed loop
- Don't modify a collection's structure (adding/removing items) while iterating over it with foreach - it throws an InvalidOperationException
- Implement IEnumerable<T> on a custom class when it genuinely represents a collection of things, so it works naturally with foreach and LINQ
- Use yield return inside GetEnumerator() (or any iterator method) for a concise way to implement custom iteration logic
At a glance
- Purpose
- Applications on the .NET platform
- File extension
- .cs
- Runs in
- .NET runtime
- Usually used with
- .NET SDK and libraries
Specifications & further reading
Related C# documentation
List<T>
List<T> is a resizable, generic collection from System.Collections.Generic, and the most commonly used collection type in C#. Unlike a plain array, a List<T> automatically grows as elements are added, and it provides a rich set of methods for adding, removing, searching, and sorting. The <T> means a List can be strongly typed to hold any specific type, like List<string> or List<int>.Dictionary<TKey, TValue>
Dictionary<TKey, TValue> stores data as key-value pairs, offering fast average-case lookup, insertion, and deletion by key, backed by a hash table. Keys must be unique - adding a value with an existing key throws an exception, while indexer assignment (dict[key] = value) overwrites it instead. Dictionary does not guarantee any particular iteration order.Queue<T> & Stack<T>
Queue<T> is a first-in-first-out (FIFO) collection - items are added with Enqueue() and removed with Dequeue(), just like a real-world line. Stack<T> is last-in-first-out (LIFO) - items are added with Push() and removed with Pop(), like a stack of plates. Both are useful for specific processing orders where a general-purpose List<T> would require extra bookkeeping.HashSet<T>
HashSet<T> is a collection that stores unique elements with no guaranteed ordering, backed by a hash table. Adding a duplicate element has no effect, since HashSet automatically enforces uniqueness. It provides very fast average-case performance for adding, removing, and checking membership, and offers built-in set operations like union, intersection, and difference.
List<T> is a resizable, generic collection from System.Collections.Generic, and the most commonly used collection type in C#. Unlike a plain array, a List<T> automatically grows as elements are added, and it provides a rich set of methods for adding, removing, searching, and sorting. The <T> means a List can be strongly typed to hold any specific type, like List<string> or List<int>.Dictionary<TKey, TValue>
Dictionary<TKey, TValue> stores data as key-value pairs, offering fast average-case lookup, insertion, and deletion by key, backed by a hash table. Keys must be unique - adding a value with an existing key throws an exception, while indexer assignment (dict[key] = value) overwrites it instead. Dictionary does not guarantee any particular iteration order.Queue<T> & Stack<T>
Queue<T> is a first-in-first-out (FIFO) collection - items are added with Enqueue() and removed with Dequeue(), just like a real-world line. Stack<T> is last-in-first-out (LIFO) - items are added with Push() and removed with Pop(), like a stack of plates. Both are useful for specific processing orders where a general-purpose List<T> would require extra bookkeeping.HashSet<T>
HashSet<T> is a collection that stores unique elements with no guaranteed ordering, backed by a hash table. Adding a duplicate element has no effect, since HashSet automatically enforces uniqueness. It provides very fast average-case performance for adding, removing, and checking membership, and offers built-in set operations like union, intersection, and difference.