The Enumerable Enumerator






4.80/5 (21 votes)
Nov 2, 2006
2 min read

57652

321
Iterate over your enums, and other things to do with enums.
Introduction
The Enumerable Enumerator is something I threw together to address a need to iterate and sequence through enumerations. I find this class useful when working with hardware and dealing with such things as bit fields. I also found application for this class in managing state and sequencing through states. For example, I may have an enumeration of bits:
enum AlarmBits
{
Door=1,
Window=2,
Security=4,
CoinJam=8,
BillJam=16,
}
and I simply want to iterate through the enumeration to test each bit.
Or, I may have a set of states:
enum States
{
Slow,
Medium,
Fast
}
and in this case, I want to be able to change state in a forward or backwards direction but not exceed the state limits. As a side benefit, I found that using the methods in this class resulted in more robust application code, as I could change the enumeration without having to go back and update the application code. If I add an alarm bit or a state, I'm only changing the enumeration, not the code that implements iterating through the enumeration or managing a state.
The Code
The class Enumerator
consists of the following properties and methods. All the examples use this enum:
enum Test
{
A=1,
B=2,
C=3,
D=4,
}
You will note that all the methods are static because they operate on the enumeration type as opposed to an instance of the enumeration. The use of generics improves type checking (for example, the current value and the minimum value must be of the same type) and avoids downcasting of the returned value in the application code.
First
Returns the first value in the enumerator. As with all these methods, the enumerations are sorted by value, which may not be the same as the ordinal value.
public static T First
{
get { return ((T[])Enum.GetValues(typeof(T)))[0]; }
}
Example:
Console.WriteLine("First = " + Enumerator<Test>.First);
The output is:
First = A
Last
Returns the last enumeration value.
public static T Last
{
get
{
T[] vals = (T[])Enum.GetValues(typeof(T));
return vals[vals.Length-1];
}
}
Example:
Console.WriteLine("Last = " + Enumerator<Test>.Last);
The output is:
Last = D
PreviousOrFirst
This method returns the previous enumeration value, or returns the first value if the enumeration cannot be decremented further. I find this method, and the corresponding NextOrLast
method, useful to work with enumerators that represent state.
public static T PreviousOrFirst(T val)
{
T[] vals = (T[])Enum.GetValues(typeof(T));
int idx = Array.FindIndex<T>(vals, delegate(T v) { return v.Equals(val); });
return idx == 0 ? vals[0] : vals[idx - 1];
}
Example:
Console.WriteLine("Previous Or First of A = " +
Enumerator<Test>.PreviousOrFirst(Test.A));
Console.WriteLine("Previous Or First of B = " +
Enumerator<Test>.PreviousOrFirst(Test.B));
Outputs:
Previous Or First of A = A
Previous Or First of B = A
NextOrLast
This method is the compliment of the PreviousOrFirst
method.
public static T NextOrLast(T val)
{
T[] vals = (T[])Enum.GetValues(typeof(T));
int idx = Array.FindIndex<T>(vals, delegate(T v) { return v.Equals(val); });
return idx == vals.Length-1 ? vals[idx] : vals[idx + 1];
}
Example:
Console.WriteLine("Next Or Last of C = " +
Enumerator<Test>.NextOrLast(Test.C));
Console.WriteLine("Next Or Last of D = " +
Enumerator<Test>.NextOrLast(Test.D));
The output is:
Next Or Last of C = D
Next Or Last of D = D
PreviousBounded
It seemed reasonable to also supply a couple methods that are bounded by a supplied enum value rather than the first or last enum value.
public static T PreviousBounded(T val, T min)
{
T[] vals = (T[])Enum.GetValues(typeof(T));
int curIdx = Array.FindIndex<T>(vals, delegate(T v) {return v.Equals(val);});
int minIdx = Array.FindIndex<T>(vals, delegate(T v) {return v.Equals(min);});
return curIdx <= minIdx ? vals[minIdx] : vals[curIdx - 1];
}
Example:
Console.WriteLine("Enumerator low limit (C->B) = " +
Enumerator<Test>.PreviousBounded(Test.C, Test.B));
Console.WriteLine("Enumerator low limit (B->B) = " +
Enumerator<Test>.PreviousBounded(Test.B, Test.B));
Console.WriteLine("Enumerator low limit (A->B) = " +
Enumerator<Test>.PreviousBounded(Test.A, Test.B));
The output is:
Enumerator low limit (C->B) = B
Enumerator low limit (B->B) = B
Enumerator low limit (A->B) = B
NextBounded
public static T NextBounded(T val, T max) { T[] vals = (T[])Enum.GetValues(typeof(T)); int curIdx = Array.FindIndex<T>(vals, delegate(T v) { return v.Equals(val); }); int maxIdx = Array.FindIndex<T>(vals, delegate(T v) { return v.Equals(max); }); return curIdx >= maxIdx ? vals[maxIdx] : vals[curIdx + 1]; }
Example:
Console.WriteLine("Enumerator high limit (B->C) = " +
Enumerator<Test>.NextBounded(Test.B, Test.C));
Console.WriteLine("Enumerator high limit (C->C) = " +
Enumerator<Test>.NextBounded(Test.C, Test.C));
Console.WriteLine("Enumerator high limit (D->C) = " +
Enumerator<Test>.NextBounded(Test.D, Test.C));
The output is:
Enumerator high limit (B->C) = C
Enumerator high limit (C->C) = C
Enumerator high limit (D->C) = C
Enumerating
The original goal was simply to be able to iterate over the enumeration (changed as per the suggestions in the comments):
public static IEnumerable<T> Items()
{
return (T[])Enum.GetValues(typeof(T));
}
Example:
foreach (Test t in Enumerator<Test>.Items())
{
Console.WriteLine(t + " = " + Convert.ToInt32(t));
}
The output is:
A = 1
B = 2
C = 3
D = 4
Conclusion
So, it's a simple class but it was fun to write, provides some useful functionality, and helps to decouple the enumeration implementation from the application logic, which is something I always find useful.