Click here to Skip to main content
13,550,585 members
Click here to Skip to main content
Add your own
alternative version


44 bookmarked
Posted 2 Nov 2006

The Enumerable Enumerator

, 2 Nov 2006
Rate this:
Please Sign up or sign in to vote.
Iterate over your enums, and other things to do with enums.


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

and I simply want to iterate through the enumeration to test each bit.

Or, I may have a set of states:

enum States

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

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.


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]; }


Console.WriteLine("First = " + Enumerator<Test>.First);

The output is:

First = A


Returns the last enumeration value.

public static T Last
    T[] vals = (T[])Enum.GetValues(typeof(T));
    return vals[vals.Length-1]; 


Console.WriteLine("Last = " + Enumerator<Test>.Last);

The output is:

Last = D


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];


Console.WriteLine("Previous Or First of A = " + 
Console.WriteLine("Previous Or First of B = " + 


Previous Or First of A = A
Previous Or First of B = A


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];


Console.WriteLine("Next Or Last of C = " + 
Console.WriteLine("Next Or Last of D = " + 

The output is:

Next Or Last of C = D
Next Or Last of D = D


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];


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


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];


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


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));


foreach (Test t in Enumerator<Test>.Items())
  Console.WriteLine(t + " = " + Convert.ToInt32(t));

The output is:

A = 1
B = 2
C = 3
D = 4


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.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Marc Clifton
United States United States
Marc is the creator of two open source projects, MyXaml, a declarative (XML) instantiation engine and the Advanced Unit Testing framework, and Interacx, a commercial n-tier RAD application suite.  Visit his website,, where you will find many of his articles and his blog.

Marc lives in Philmont, NY.

You may also be interested in...

Comments and Discussions

Generalpet peeve Pin
wurakeem10-Nov-06 8:40
memberwurakeem10-Nov-06 8:40 
GeneralRe: pet peeve Pin
Marc Clifton10-Nov-06 9:28
protectorMarc Clifton10-Nov-06 9:28 
GeneralSuggestion Pin
Steve Hansen2-Nov-06 6:31
memberSteve Hansen2-Nov-06 6:31 
GeneralRe: Suggestion Pin
Christian Klauser2-Nov-06 6:49
memberChristian Klauser2-Nov-06 6:49 
GeneralRe: Suggestion Pin
Marc Clifton2-Nov-06 8:23
protectorMarc Clifton2-Nov-06 8:23 
GeneralRe: Suggestion Pin
Marc Clifton2-Nov-06 8:20
protectorMarc Clifton2-Nov-06 8:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.180515.1 | Last Updated 2 Nov 2006
Article Copyright 2006 by Marc Clifton
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid