C# foreach
last modified October 18, 2026
In this article we show how to loop over data in C# with the foreach
statement and the ForEach method.
foreach (var val in vals)
{
...
}
The foreach statement executes a statement or a block of statements for
each element of a collection. The collection can be anything that has a
GetEnumerator method: it implements IEnumerable or
IEnumerable<T>, or follows the same pattern, like arrays and
Span<T>. The iteration variable is read-only.
public void ForEach(Action<T> action);
The List<T>.ForEach method performs the specified action on each
element of the list. A similar method exists for arrays: Array.ForEach.
There is no ForEach method for a general IEnumerable<T>.
The foreach statement is the preferred way to loop, as it supports
break, continue, return, and
await, which the ForEach methods do not.
C# foreach array
In the following example, we go over the elements of an array using the
foreach statement.
int[] vals = [1, 2, 3, 4, 5];
foreach (var val in vals)
{
Console.WriteLine(val);
}
// the iteration variable is read-only
foreach (var val in vals)
{
// val = 10; // error CS1656: cannot assign to 'val' because it is a 'foreach iteration variable'
Console.Write($"{val * 2} ");
}
Console.WriteLine();
The example prints all elements of an array of integers, and then the doubled values.
foreach (var val in vals)
{
// val = 10;
The iteration variable cannot be assigned, a compile-time error (CS1656). To change
the elements of an array, use a for loop with an index. (If the element
is a reference type or a class instance, its properties can be changed, as shown
below.)
$ dotnet run 1 2 3 4 5 2 4 6 8 10
C# foreach multidimensional array
The next example loops over a two-dimensional array and a jagged array.
int[,] vals =
{
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10},
{11, 12, 13, 14, 15}
};
foreach (var e in vals)
{
Console.Write($"{e} ");
}
Console.WriteLine();
Console.WriteLine("------------------------------------");
for (int i = 0; i < vals.GetLength(0); i++)
{
for (int j = 0; j < vals.GetLength(1); j++)
{
Console.Write($"{vals[i, j],3}");
}
Console.WriteLine();
}
Console.WriteLine("------------------------------------");
// a jagged array is an array of arrays
int[][] jagged = [[1, 2], [3, 4, 5], [6]];
foreach (int[] row in jagged)
{
foreach (int e in row)
{
Console.Write($"{e} ");
}
Console.WriteLine();
}
We have a two-dimensional array of integers. We loop over the values in several ways.
foreach (var e in vals)
{
Console.Write($"{e} ");
}
A foreach over a rectangular array visits all elements in row-major
order, row after row, as one flat sequence.
for (int i = 0; i < vals.GetLength(0); i++)
{
for (int j = 0; j < vals.GetLength(1); j++)
{
Console.Write($"{vals[i, j],3}");
}
Console.WriteLine();
}
To keep the row structure, we use two nested for loops;
GetLength(0) is the number of rows and GetLength(1) the
number of columns. The alignment component ,3 right-aligns each number
in a field three characters wide.
int[][] jagged = [[1, 2], [3, 4, 5], [6]];
foreach (int[] row in jagged)
{
foreach (int e in row)
A jagged array is an array of arrays; its rows may have different lengths. Two
nested foreach loops traverse it naturally.
$ dotnet run 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ------------------------------------ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ------------------------------------ 1 2 3 4 5 6
C# foreach List
In the following example, we loop over a list with the foreach
statement.
List<string> words = ["tea", "falcon", "book", "sky"];
foreach (var word in words)
{
Console.WriteLine(word);
}
Console.WriteLine("--");
// with an index
foreach (var (word, index) in words.Select((w, i) => (w, i)))
{
Console.WriteLine($"{index}: {word}");
}
Console.WriteLine("--");
// break and continue
foreach (var word in words)
{
if (word == "book")
{
continue;
}
if (word == "sky")
{
break;
}
Console.WriteLine(word);
}
// reversed and ordered
foreach (var word in words.AsEnumerable().Reverse())
{
Console.Write($"{word} ");
}
Console.WriteLine();
foreach (var word in words.OrderBy(w => w.Length).ThenBy(w => w))
{
Console.Write($"{word} ");
}
Console.WriteLine();
We print the elements of a list of strings in several ways.
foreach (var (word, index) in words.Select((w, i) => (w, i)))
{
Console.WriteLine($"{index}: {word}");
}
The foreach statement does not provide an index. When we need one, the
LINQ Select overload with an index builds pairs, which are deconstructed
in the loop header. Alternatively, we use a for loop.
if (word == "book")
{
continue;
}
if (word == "sky")
{
break;
}
The continue statement skips to the next element, and
break leaves the loop. Here, the book is skipped and the loop ends at
the sky.
foreach (var word in words.AsEnumerable().Reverse()) foreach (var word in words.OrderBy(w => w.Length).ThenBy(w => w))
LINQ operators give another order to the loop without changing the list. The
AsEnumerable call makes sure that the LINQ Reverse is used
and not the in-place span method of newer C# versions.
$ dotnet run tea falcon book sky -- 0: tea 1: falcon 2: book 3: sky -- tea falcon sky book falcon tea sky tea book falcon
C# foreach list of lists
In the next example, we loop over a list of lists.
List<List<string>> words =
[
["tea", "falcon", "book", "sky"],
["cup", "crown", "borrow", "moore"],
["arm", "nice", "frost", "sea"]
];
foreach (var nested in words)
{
foreach (var word in nested)
{
Console.Write($"{word} ");
}
Console.WriteLine();
}
// flatten with SelectMany
foreach (var word in words.SelectMany(w => w).Where(w => w.Length > 5))
{
Console.WriteLine(word);
}
To iterate over a list of lists, we use two foreach loops. When we do
not need the row structure, LINQ's SelectMany flattens the nested
collection into a single sequence, and a single loop is enough.
$ dotnet run tea falcon book sky cup crown borrow moore arm nice frost sea falcon borrow
C# foreach Dictionary
The following example loops over the elements of a dictionary with the
foreach statement.
var domains = new Dictionary<string, string>
{
{"sk", "Slovakia"},
{"ru", "Russia"},
{"de", "Germany"},
{"no", "Norway"}
};
foreach (var pair in domains)
{
Console.WriteLine($"{pair.Key} - {pair.Value}");
}
Console.WriteLine("-----------------------");
foreach (var (key, value) in domains)
{
Console.WriteLine($"{key} - {value}");
}
Console.WriteLine("-----------------------");
foreach (var key in domains.Keys.Order())
{
Console.WriteLine($"{key} - {domains[key]}");
}
Console.WriteLine("-----------------------");
foreach (var value in domains.Values.OrderByDescending(v => v))
{
Console.Write($"{value} ");
}
Console.WriteLine();
We have a dictionary of domains. The elements of a dictionary are
KeyValuePair<TKey, TValue> structures.
foreach (var (key, value) in domains)
{
Console.WriteLine($"{key} - {value}");
}
A KeyValuePair can be deconstructed into the key and the value directly
in the loop header, which makes the body shorter. The earlier form with
pair.Key and pair.Value is equivalent.
foreach (var key in domains.Keys.Order())
{
Console.WriteLine($"{key} - {domains[key]}");
}
A Dictionary does not guarantee any order of its elements; in practice,
it is the order of insertion when nothing has been removed. If an order matters, we
sort the keys or the values, here with the Order method (.NET 7). A
SortedDictionary keeps the keys sorted all the time.
$ dotnet run sk - Slovakia ru - Russia de - Germany no - Norway ----------------------- sk - Slovakia ru - Russia de - Germany no - Norway ----------------------- de - Germany no - Norway ru - Russia sk - Slovakia ----------------------- Slovakia Russia Norway Germany
C# foreach over other sequences
We can use foreach with many types: strings, the results of LINQ
queries, ranges, spans, file system enumerations, and so on.
// foreach over a string, a range, and the result of a LINQ query
foreach (char c in "falcon")
{
Console.Write($"{char.ToUpper(c)} ");
}
Console.WriteLine();
foreach (int i in Enumerable.Range(1, 5))
{
Console.Write($"{i * i} ");
}
Console.WriteLine();
foreach (var line in "one\ntwo\nthree".Split('\n'))
{
Console.WriteLine(line.Length);
}
// over a span: no allocations
ReadOnlySpan<int> span = [10, 20, 30];
foreach (var e in span)
{
Console.Write($"{e} ");
}
Console.WriteLine();
The example loops over a string, a numeric range, an array of lines, and a span.
ReadOnlySpan<int> span = [10, 20, 30];
foreach (var e in span)
{
Console.Write($"{e} ");
}
A Span<T> is a ref struct with a
GetEnumerator method; the loop does not allocate any memory. This is the
pattern-based side of foreach: no interface is needed.
$ dotnet run F A L C O N 1 4 9 16 25 3 3 5 10 20 30
C# foreach and modifying the collection
We must not add or remove elements of a collection while we enumerate it with
foreach. The enumerator detects the change and throws an
InvalidOperationException on the next step.
List<int> numbers = [1, 2, 3, 4, 5, 6];
try
{
foreach (var n in numbers)
{
if (n % 2 == 0)
{
numbers.Remove(n); // changes the collection during the enumeration
}
}
}
catch (InvalidOperationException e)
{
Console.WriteLine(e.Message);
}
// remove with RemoveAll, or enumerate a copy
numbers.RemoveAll(n => n % 2 == 0);
Console.WriteLine(string.Join(", ", numbers));
List<int> numbers2 = [1, 2, 3, 4, 5, 6];
foreach (var n in numbers2.ToList())
{
if (n % 2 == 0)
{
numbers2.Remove(n);
}
}
Console.WriteLine(string.Join(", ", numbers2));
// a for loop going backwards also works
List<int> numbers3 = [1, 2, 3, 4, 5, 6];
for (int i = numbers3.Count - 1; i >= 0; i--)
{
if (numbers3[i] % 2 == 0)
{
numbers3.RemoveAt(i);
}
}
Console.WriteLine(string.Join(", ", numbers3));
// modifying the properties of the elements is fine
var people = new List<Person> { new("John", 30), new("Jane", 25) };
foreach (var p in people)
{
p.Age++;
}
Console.WriteLine(string.Join(", ", people));
class Person(string name, int age)
{
public int Age { get; set; } = age;
public override string ToString() => $"{name} {Age}";
}
The example tries to remove the even numbers from a list in the loop, and then shows three ways that work.
numbers.RemoveAll(n => n % 2 == 0);
RemoveAll is the shortest way for a list. Another way is to enumerate
a copy of the list (numbers.ToList()) while changing the original, or a
for loop that goes backwards, so that the removal does not shift the
indexes that are still to be visited.
foreach (var p in people)
{
p.Age++;
}
Changing the properties of the elements is fine, as long as the elements are reference types. For a collection of structures, the loop variable is a copy, and the change is lost (and the compiler rejects changing its field).
$ dotnet run Collection was modified; enumeration operation may not execute. 1, 3, 5 1, 3, 5 1, 3, 5 John 31, Jane 26
C# foreach with custom collections
Our own types can be used in foreach by implementing
IEnumerable<T>, or just by having a suitable
GetEnumerator method. The easiest way to write the enumerator is an
iterator method with yield return.
// foreach works with any type that has a GetEnumerator method
var countdown = new Countdown(5);
foreach (var n in countdown)
{
Console.Write($"{n} ");
}
Console.WriteLine();
foreach (var w in new Words("an old falcon in the sky"))
{
Console.WriteLine(w);
}
// an iterator method with yield return
foreach (var n in Fibonacci().Take(10))
{
Console.Write($"{n} ");
}
Console.WriteLine();
IEnumerable<long> Fibonacci()
{
long a = 0, b = 1;
while (true)
{
yield return a;
(a, b) = (b, a + b);
}
}
class Countdown(int from) : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
for (int i = from; i > 0; i--)
{
yield return i;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
}
// duck typing: only a GetEnumerator method with Current and MoveNext is needed
class Words(string text)
{
public IEnumerator<string> GetEnumerator() => text.Split(' ').AsEnumerable().GetEnumerator();
}
The example defines a countdown collection, a class that only has a
GetEnumerator method, and an infinite sequence of Fibonacci numbers.
IEnumerable<long> Fibonacci()
{
long a = 0, b = 1;
while (true)
{
yield return a;
(a, b) = (b, a + b);
}
}
An iterator method runs only as far as the consumer asks. The sequence is infinite,
but Take(10) stops after ten elements. Nothing is computed ahead of time
and nothing is stored.
$ dotnet run 5 4 3 2 1 an old falcon in the sky 0 1 1 2 3 5 8 13 21 34
C# await foreach
The await foreach statement (C# 8) consumes an asynchronous stream, an
IAsyncEnumerable<T>. Elements arrive over time, for example from a
network or a database, and the loop waits for each of them without blocking a
thread.
// await foreach consumes an asynchronous stream
await foreach (var n in ReadAsync())
{
Console.WriteLine($"received {n}");
}
// asynchronous streams can be cancelled
using var cts = new CancellationTokenSource(350);
try
{
await foreach (var n in ReadAsync(cts.Token))
{
Console.WriteLine($"again {n}");
}
}
catch (OperationCanceledException)
{
Console.WriteLine("canceled");
}
async IAsyncEnumerable<int> ReadAsync([System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken token = default)
{
for (int i = 1; i <= 3; i++)
{
await Task.Delay(200, token);
yield return i;
}
}
The program reads three numbers that arrive with a delay, and then a second time with a timeout.
async IAsyncEnumerable<int> ReadAsync([EnumeratorCancellation] CancellationToken token = default)
An asynchronous iterator combines async, await, and
yield return. The attribute EnumeratorCancellation connects
the token passed through WithCancellation on the consumer side with the
parameter of the method. In the example, the token comes from the argument, and the
cancellation ends the loop with an OperationCanceledException after the
first element.
$ dotnet run received 1 received 2 received 3 again 1 canceled
C# ForEach method
The ForEach methods of arrays and lists run a delegate for each
element. They are fine for short statements, but they are less flexible than the
statement.
int[] vals = [1, 2, 3, 4, 5];
Array.ForEach(vals, e => Console.Write($"{e} "));
Console.WriteLine();
List<string> words = ["tea", "falcon", "book", "sky"];
words.ForEach(e => Console.Write($"{e} "));
Console.WriteLine();
// a method group works too
words.ForEach(Console.WriteLine);
var domains = new Dictionary<string, string>
{
{"sk", "Slovakia"},
{"ru", "Russia"}
};
domains.ToList().ForEach(pair => Console.WriteLine($"{pair.Key} - {pair.Value}"));
// there is no ForEach on IEnumerable<T>; we can write our own, but a foreach statement is clearer
IEnumerable<int> seq = Enumerable.Range(1, 3);
// seq.ForEach(...) // error CS1061: IEnumerable<int> does not contain a definition for 'ForEach'
foreach (var s in seq) Console.Write($"{s} ");
Console.WriteLine();
// a ForEach lambda cannot break or return from the outer method
int sum = 0;
vals.ToList().ForEach(v => { if (v > 3) return; sum += v; }); // return only leaves the lambda
Console.WriteLine(sum);
The program uses Array.ForEach and List<T>.ForEach.
words.ForEach(Console.WriteLine);
A method group can be passed instead of a lambda.
domains.ToList().ForEach(pair => Console.WriteLine($"{pair.Key} - {pair.Value}"));
For a dictionary, which has no ForEach, we first copy the elements to a
list with LINQ's ToList. The extra copy makes this form worse than a
plain foreach.
vals.ToList().ForEach(v => { if (v > 3) return; sum += v; });
The limits of the method show here. A return inside the lambda leaves
only the lambda, so it works like continue; there is no way to
break out of the loop. We also cannot use await in a useful
way. And the lambda can capture variables of the outer method, which allocates a
closure. For these reasons, most style guides recommend the
foreach statement.
$ dotnet run 1 2 3 4 5 tea falcon book sky tea falcon book sky sk - Slovakia ru - Russia 1 2 3 6
C# Parallel.ForEach
For CPU-bound work on large collections, Parallel.ForEach spreads the
iterations over several threads. The order of the iterations is not defined. For
asynchronous work, there is Parallel.ForEachAsync with a limit on the
concurrency.
using System.Diagnostics;
var items = Enumerable.Range(1, 8).ToList();
// Parallel.ForEach spreads the iterations over the thread pool: the order is not defined
var bag = new System.Collections.Concurrent.ConcurrentBag<int>();
Parallel.ForEach(items, i => bag.Add(i * i));
Console.WriteLine(string.Join(", ", bag.Order()));
// Parallel.ForEachAsync for asynchronous work with a limit
var sw = Stopwatch.StartNew();
await Parallel.ForEachAsync(items, new ParallelOptions { MaxDegreeOfParallelism = 4 }, async (i, ct) =>
{
await Task.Delay(100, ct);
});
Console.WriteLine($"8 delays of 100 ms with 4 workers: about {sw.ElapsedMilliseconds / 100 * 100} ms");
// do not await in a List.ForEach lambda: the lambda becomes async void
// items.ForEach(async i => await Task.Delay(100)); // fire-and-forget, exceptions crash the process
// a plain foreach with await runs one at a time
sw.Restart();
foreach (var i in items.Take(3))
{
await Task.Delay(100);
}
Console.WriteLine($"3 sequential delays: about {sw.ElapsedMilliseconds / 100 * 100} ms");
The program squares numbers in parallel and runs asynchronous delays with four workers.
var bag = new System.Collections.Concurrent.ConcurrentBag<int>(); Parallel.ForEach(items, i => bag.Add(i * i));
The body runs on several threads at once, so any shared state needs a thread-safe
collection, here a ConcurrentBag; adding to a plain
List from the loop would be a data race. We sort the result, since the
bag has no order.
// items.ForEach(async i => await Task.Delay(100));
An async lambda passed to List.ForEach becomes an
async void method: the call does not wait for the work, and an
exception in it can crash the process. Use Parallel.ForEachAsync for
concurrent work or a plain foreach with await for
sequential work, as the last part of the example shows.
$ dotnet run 1, 4, 9, 16, 25, 36, 49, 64 8 delays of 100 ms with 4 workers: about 200 ms 3 sequential delays: about 300 ms
Source
In this article we have covered the foreach statement and the
ForEach method in C#.
Author
List all C# tutorials.