Click here to Skip to main content
Click here to Skip to main content
Go to top

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 projets, 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.

Comments and Discussions

Generalpet peeve Pinmemberwurakeem10-Nov-06 8:40 
GeneralRe: pet peeve PinprotectorMarc Clifton10-Nov-06 9:28 
wurakeem wrote:
I don't mean to be pedantic about unimportant things but the category of the article does not specify that this is .NET 2.0 code.

True. There is no option for .NET 1.1 vs. 2.0 compatible code.
wurakeem wrote:
I assumed it was .NET 1.1 compatible which is something I could've used.

Well, not to be obnoxious, but I basically assume, since .NET 2.0 has been out now for a couple years and .NET 3.0 has just been released, that people are using .NET 2.0.
BTW, the actual issue, the support of templates, is not a .NET 1.1 /2.0 issue, but C# 1.0 vs 2.0 (ie., VS2003 vs VS2005). I can understand that people are still using VS2003, but frankly, I would considering upgrading.

Thyme In The Country

People are just notoriously impossible. --DavidCrow
There's NO excuse for not commenting your code. -- John Simmons / outlaw programmer
People who say that they will refactor their code later to make it "good" don't understand refactoring, nor the art and craft of programming. -- Josh Smith

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.140905.1 | Last Updated 2 Nov 2006
Article Copyright 2006 by Marc Clifton
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid