Introduction
I quite often see constructs like:
for(int n = 0; n < len; ++n)
{
n = 5;
}
This is a legal language construct, but it introduces the danger of non-determinism.
This tip aims to show some deterministic alternatives to that plain for
loop.
Using the Code
If you need to loop over some range of integer, consider using the Enumerable.Range[^] based foreach
loop instead:
using System.Linq;
...
foreach (int n in Enumerable.Range(0, len))
{
...
}
This guarantees that it iterates over all elements in strict sequence. Another benefit is that you cannot assign any other value to the loop variable n
. E.g.
foreach (int n in Enumerable.Range(0, len))
{
n = 5;
}
Note: Enumerable.Range(...)
is not from, to, but from, count:
public static IEnumerable<int> Range(int start, int count);
Alternatives
One could also build his own iterator functions (see also C# Iterator Pattern demystified[^]). E.g.
public static IEnumerable<int> CountUp(int n, int count)
{
while (count-- > 0) yield return n++;
}
public static IEnumerable<int> CountDown(int n, int count)
{
while (count-- > 0) yield return n--;
}
When used like this...
foreach (int n in CountUp(0, 5)) Console.WriteLine(n);
foreach (int n in CountDown(100, 5)) Console.WriteLine(n);
...results in:
0
1
2
3
4
100
99
98
97
96
You can define any complexity of traversing sequence in that function and let the foreach
-loop terminate deterministically, based on that sequence.
Advise
Try to avoid plain for (...)
loops and replace by some deterministic loop alternative like:
foreach( ... Range(...))
foreach( ... CountUp(...))
- etc.
Other alternatives are Linq iterations like Enumerable.Aggregate[^] etc. But these are a bit more advanced.
History
- 2012-04-18 First version
- 2012-04-19 Added hand-crafted
CountUp
/CountDown
functions - 2013-04-14 Fixed some broken HTML markup in C# code generics