When to Use foreach vs for Loop in C#
foreach is designed for iterating through collections and is more readable for simple traversal. for loops provide more control with index access, reverse iteration, and custom step sizes.
Use foreach when you need to iterate through all elements of a collection without needing the index. Use for when you need the index, want to iterate in reverse, skip elements, or modify the collection.
foreach is safer (can't access out of bounds) and cleaner for most scenarios. for loops are more flexible and slightly faster with arrays due to bounds checking optimization.
Basic Iteration Comparison
// Simple iteration - foreach is cleaner
Console.WriteLine("=== Simple iteration - foreach ===");
string[] fruits = { "Apple", "Banana", "Cherry", "Date" };
foreach (string fruit in fruits)
{
Console.WriteLine(fruit);
}
// Same with for - more verbose
Console.WriteLine("\n=== Same with for loop ===");
for (int i = 0; i < fruits.Length; i++)
{
Console.WriteLine(fruits[i]);
}When You Need the Index
// When you need the index - use for
Console.WriteLine("\n=== When index is needed - use for ===");
for (int i = 0; i < fruits.Length; i++)
{
Console.WriteLine($"Index {i}: {fruits[i]}");
}
// Alternative: foreach with LINQ Select
Console.WriteLine("\n=== foreach with index using LINQ ===");
foreach (var (fruit, index) in fruits.Select((f, i) => (f, i)))
{
Console.WriteLine($"Index {index}: {fruit}");
}Reverse Iteration and Skipping Elements
// Reverse iteration - for is better
Console.WriteLine("\n=== Reverse iteration - use for ===");
for (int i = fruits.Length - 1; i >= 0; i--)
{
Console.WriteLine(fruits[i]);
}
// Skip elements - for is better
Console.WriteLine("\n=== Every other element - use for ===");
for (int i = 0; i < fruits.Length; i += 2)
{
Console.WriteLine(fruits[i]);
}Modifying Collections During Iteration
// Modifying collection - careful with foreach!
Console.WriteLine("\n=== Modifying during iteration ===");
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
// for loop - safe to modify
for (int i = numbers.Count - 1; i >= 0; i--)
{
if (numbers[i] % 2 == 0)
{
numbers.RemoveAt(i);
}
}
Console.WriteLine($"After removing evens: {string.Join(", ", numbers)}");
// foreach would throw exception if modifying
// foreach (int num in numbers) // Don't do this!
// {
// numbers.Remove(num); // InvalidOperationException
// }Nested Loops and Breaking
// Nested loops - both work
Console.WriteLine("\n=== Nested loops ===");
int[,] matrix = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
Console.WriteLine("Using for:");
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
Console.Write($"{matrix[i, j]} ");
}
Console.WriteLine();
}
// Breaking out of loops
Console.WriteLine("\n=== Breaking with condition ===");
string[] words = { "hello", "world", "stop", "here", "now" };
Console.WriteLine("foreach with break:");
foreach (string word in words)
{
if (word == "stop") break;
Console.WriteLine(word);
}
Console.WriteLine("\nfor with break:");
for (int i = 0; i < words.Length; i++)
{
if (words[i] == "stop") break;
Console.WriteLine(words[i]);
}Performance Comparison
// Performance comparison
Console.WriteLine("\n=== Performance notes ===");
PerformanceComparison();
static void PerformanceComparison()
{
int[] largeArray = new int[1000000];
for (int i = 0; i < largeArray.Length; i++)
{
largeArray[i] = i;
}
// for loop with array - optimized by compiler
var watch = System.Diagnostics.Stopwatch.StartNew();
long sum1 = 0;
for (int i = 0; i < largeArray.Length; i++)
{
sum1 += largeArray[i];
}
watch.Stop();
long forTime = watch.ElapsedMilliseconds;
// foreach with array
watch.Restart();
long sum2 = 0;
foreach (int num in largeArray)
{
sum2 += num;
}
watch.Stop();
long foreachTime = watch.ElapsedMilliseconds;
Console.WriteLine($"for loop: {forTime}ms");
Console.WriteLine($"foreach: {foreachTime}ms");
Console.WriteLine("Performance is similar for arrays (both are optimized)");
}Using foreach with Different Collection Types
// foreach with different collection types
Console.WriteLine("\n=== foreach with different collections ===");
// List
List<string> list = new List<string> { "A", "B", "C" };
foreach (string item in list)
{
Console.Write($"{item} ");
}
Console.WriteLine();
// Dictionary
Dictionary<string, int> dict = new Dictionary<string, int>
{
{ "One", 1 },
{ "Two", 2 }
};
foreach (KeyValuePair<string, int> kvp in dict)
{
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
// HashSet
HashSet<int> set = new HashSet<int> { 1, 2, 3 };
foreach (int num in set)
{
Console.Write($"{num} ");
}
Console.WriteLine();Custom Iteration Patterns with for
// Custom step and conditions with for
Console.WriteLine("\n=== Custom iteration patterns ===");
Console.WriteLine("Every third element:");
for (int i = 0; i < 20; i += 3)
{
Console.Write($"{i} ");
}
Console.WriteLine();
// Multiple variables in for
Console.WriteLine("\nTwo variables:");
for (int i = 0, j = 10; i < 5; i++, j--)
{
Console.WriteLine($"i={i}, j={j}");
}Usage Guidelines
Use foreach when:
- Iterating all elements in order
- Don't need the index
- Not modifying the collection
- Working with IEnumerable
Use for when:
- Need the index
- Iterating backwards
- Custom step size
- Modifying collection during iteration
- Need maximum performance with arrays
Take It Further

The community's favorite C# guide — teaches every concept you just read about with clarity.
The C# Player's Guide — 5th Edition · RB Whitaker
Get it on Amazon →As an Amazon Associate I earn from qualifying purchases.