I have an enum which is defined like this:
public enum eRat { A = 0, B=3, C=5, D=8 };
So given value eRat.B
, I want to get the
Probably a bit overkill, but:
eRat value = eRat.B;
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.SkipWhile(e => e != value).Skip(1).First();
or if you want the first that is numerically bigger:
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.First(e => (int)e > (int)value);
or for the next bigger numerically (doing the sort ourselves):
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.Where(e => (int)e > (int)value).OrderBy(e => e).First();
Hey, with LINQ as your hammer, the world is full of nails ;-p
Do you really need to generalize this problem? Can you just do this instead?
public void SomeMethod(MyEnum myEnum)
{
MyEnum? nextMyEnum = myEnum.Next();
if (nextMyEnum.HasValue)
{
...
}
}
public static MyEnum? Next(this MyEnum myEnum)
{
switch (myEnum)
{
case MyEnum.A:
return MyEnum.B;
case MyEnum.B:
return MyEnum.C;
case MyEnum.C:
return MyEnum.D;
default:
return null;
}
}
Are you locked into using an enum by something that you have no control over?
If you're not, I'd suggest using an alternative, probably Dictionary<string, int> rat;
If you create a Dictionary
and you populate it with your data, enumerating over it is somewhat simpler. Also, it's a clearer mapping of intent-- you're mapping numbers to strings with this enum and you're trying to leverage that mapping.
If you must use the enum, I'd suggest something else:
var rats = new List<eRat>() {eRat.A, eRat.B, eRat.C, eRat.D};
As long as you're adding the values in-order and you keep it in sync, you greatly simplify the act of retrieving the next eRat.
I would go with Sung Meister's answer but here is an alternative:
MyEnum initial = MyEnum.B, next;
for (int i = ((int) initial) + 1, i < int.MaxValue; i++)
{
if (Enum.IsDefined(typeof(MyEnum), (MyEnum) i))
{
next = (MyEnum) i;
break;
}
}
Note: many assumptions assumed :)
You could simplify it and generalize it some:
static Enum GetNextValue(Enum e){
Array all = Enum.GetValues(e.GetType());
int i = Array.IndexOf(all, e);
if(i < 0)
throw new InvalidEnumArgumentException();
if(i == all.Length - 1)
throw new ArgumentException("No more values", "e");
return (Enum)all.GetValue(i + 1);
}
EDIT: Note that if your enum contains duplicate values (synonymous entries), then this (or any other technique listed here) will fail, given one of those values. For instance:
enum BRUSHSTYLE{
SOLID = 0,
HOLLOW = 1,
NULL = 1,
HATCHED = 2,
PATTERN = 3,
DIBPATTERN = 5,
DIBPATTERNPT = 6,
PATTERN8X8 = 7,
DIBPATTERN8X8 = 8
}
Given either BRUSHSTYLE.NULL
or BRUSHSTYLE.HOLLOW
, the return value would be BRUSHSTYLE.HOLLOW
.
<leppie>
Update: a generics version:
static T GetNextValue<T>(T e) { T[] all = (T[]) Enum.GetValues(typeof(T)); int i = Array.IndexOf(all, e); if (i < 0) throw new InvalidEnumArgumentException(); if (i == all.Length - 1) throw new ArgumentException("No more values", "e"); return all[i + 1]; }
</leppie>
@leppie:
Your generic version allows one to accidentally pass a non-enum value, which will be caught only at run-time. I had originally written it as a generic, but when the compiler rejected where T : Enum
, I took it out and realized that I wasn't gaining much from generics anyway. The only real drawback is that you have to cast the result back to your specific enum type.
There is a very simple solution (if you can change your integer values) that is specifically designed to work with numbers. The fact that your number is an enum
, isn't a problem. It is still the integer
(or whatever underlying number type you assign). Enum
just adds the complexity of a cast requirement.
Assume your enum
is defined like this:
public enum ItemStatus
{
New = 0,
Draft = 1,
Received = 2,
Review = 4,
Rejected = 8,
Approved = 16
}
ItemStatus myStatus = ItemStatus.Draft;
Use bitwise operations on the Enum
. For Example:
myStatus = (ItemStatus)(((int)myStatus) << 1)
The result is of myStatus is: ItemStatus.Received.
You can also go backwards down the Enum
by changing the bitwise operator from <<
to >>
.
myStatus = (ItemStatus)(((int)myStatus) >> 1)
The result is of myStatus is: ItemStatus.New.
You should always add code to test for an "out of bounds" situation in both directions.
You can understand more about bitwise operations here: http://code.tutsplus.com/articles/understanding-bitwise-operators--active-11301