Convert a flagged enum to another one - c#

I have a general enum, let's say G that has some flagged values (One = 0 / Two = 1 / Three = 2 / Four = 4 / Five = 8, and so on).
I then have another enum (let's say B) that "extends" G with this kind of pattern : One = G.One / Two = G.Two / Three = G.Three / Four = G.Four (and that's all, no Five in this one).
I finally have have a last enum (let's say C) that also "extends" G with the same pattern type but other values : Three = G.Three / Four = G.Four / Five = G.Five (no One and Two in this one).
I'd like to find a generic function to convert B into C or C into B.
For example, if I have "A valsAsA = A.One | A.Three | A.Four", I'd like a function like this : "B valsAsB = convert(valsAsA);" that would gives me "B.Three | A.Four".
This should be really generic because I have not only A and B enums, but also C, D, E... with different possible enum values, but always values from the generic enum.
Is it possible without checking all possibilities and adapting the function each time I add a new enum ?
An example:
public enum General : int
{
One = 0,
Two = 1,
Three = 2,
Four = 4,
Five = 8
}
public enum A : int
{
One = General.One,
Two = General.Two,
Three = General.Three,
Four = General.Four,
}
public enum B : int
{
Three = General.Three,
Four = General.Four,
Five = General.Five
}
public enum C : int
{
One = General.One,
Three = General.Three,
Five = General.Five
}
public class Test
{
public void testConvert()
{
A valAsA = A.One | A.Three | A.Four;
B valAsB = convertFct(valAsA); // Should give me "B.Three | B.Four"
C valAsC = convertFct(valAsA); // Should give me "C.One | C.Three"
}
}
I tested that :
A valAsA = A.One | A.Three | A.Four;
C valAsC = (C)valAsA;
C valAsCReal = C.One | C.Three; // expected result
with no luck.. valAsC = 6 while valAsCReal = 2...
Thank you very much

Doing this with generics is a little tricky because it is not possible to set up a type constraint that allows enumerations in general (see this question). The best you can do is constraint to struct, IConvertible and do a runtime check, as I do in this example.
If you can cope with that part of the ugliness, the rest is fairly simple:
First, write two methods to convert to and from a General. Since your enums are bit masks, the "conversion" is actually just a binary and operation against the sum of all possible values, which you can obtain using GetValues.
Once you have performed the and operation, you can return an enum of the appropriate type by converting the integer using Enum.ToObject().
static public class ExtensionMethods
{
static public General ToGeneral<T>(this T input) where T : struct, IConvertible
{
if (!typeof(T).IsEnum) throw new ArgumentException("Input must be an enum.");
return (General)((int)(object)input & Enum.GetValues(typeof(General)).Cast<int>().Sum());
}
static public T ToEnum<T>(this General input)
{
if (!typeof(T).IsEnum) throw new ArgumentException("Output type must be an enum.");
return (T)Enum.ToObject(typeof(T), (int)input & Enum.GetValues(typeof(T)).Cast<int>().Sum());
}
}
Once those are written, conversion to and from any enum is easy:
static public TOut Convert<TIn,TOut>(TIn input) where TIn : struct, IConvertible where TOut: struct, IConvertible
{
var general = input.ToGeneral();
return general.ToEnum<TOut>();
}
Test code:
public static void Main()
{
A valAsA = A.One | A.Three | A.Four;
B valAsB = Convert<A, B>(valAsA); // Should give me "B.Three | B.Four"
C valAsC = Convert<A, C>(valAsA); // Should give me "C.One | C.Three"
Console.WriteLine("{0} should equal {1}", valAsB, (B.Three | B.Four));
Console.WriteLine("{0} should equal {1}", valAsC, (C.One | C.Three));
}
Output:
6 should equal 6
Three should equal Three
See the code in action at DotNetFiddle

Damn !!! I could create this incredible function that answer to my question but please... tell me that there is something more elegant... xD
private TRet ConvertIt<TRet, TOrig>(TOrig values) where TOrig : struct, IConvertible where TRet : struct, IConvertible
{
if (!typeof(TOrig).IsEnum ||
!typeof(TRet).IsEnum ||
!typeof(int).IsAssignableFrom(typeof(TOrig)) ||
!typeof(int).IsAssignableFrom(typeof(TRet)))
{
throw new ArgumentException("TOrig and TRet must be an enumerated type extending integer");
}
bool retEnumHasZero = false;
foreach (var flag in Enum.GetValues(typeof(TRet)))
{
if ((int)flag == 0)
{
retEnumHasZero = true;
break;
}
}
if (!retEnumHasZero)
{
throw new ArgumentException("TRet enum must have the 0 flag");
}
Dictionary<int, Enum> valsOrig = new Dictionary<int, Enum>();
foreach (var flag in Enum.GetValues(typeof(TOrig)))
{
valsOrig.Add((int)flag, (Enum)flag);
}
object valuesAsObject = values;
var valuesAsEnum = (Enum)valuesAsObject;
int returnedValue = 0;
foreach (var flag in Enum.GetValues(typeof(TRet)))
{
int flagAsInt = (int)flag;
if (valsOrig.ContainsKey(flagAsInt) && valuesAsEnum.HasFlag(valsOrig[flagAsInt]))
{
returnedValue |= flagAsInt;
}
}
return (TRet)Enum.ToObject(typeof(TRet), returnedValue);
}
Using the function :
A valAsA = A.One | A.Two | A.Three | A.Four;
C valAsC = ConvertIt<C, A>(valAsA);
Edit : This implementation looks better :
private T ConvertIt<T>(Enum values) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("Type to return must be an enumerated type");
}
if (!Enum.IsDefined(typeof(T), 0))
{
throw new ArgumentException("Type to return enum must have the 0 flag");
}
int returnedValue = 0;
foreach (var flag in Enum.GetValues(values.GetType()))
{
int flagAsInt = (int)flag;
if (values.HasFlag((Enum)flag) && Enum.IsDefined(typeof(T), flagAsInt))
{
returnedValue |= flagAsInt;
}
}
return (T)Enum.ToObject(typeof(T), returnedValue);
}
Using the function :
A valAsA = A.One | A.Two | A.Three | A.Four;
C valAsC = ConvertIt<C>(valAsA);
Finally, with the help of John Wu, here is the final function =>
private T ConvertIt<T>(Enum input) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("Type to return must be an enumerated type");
}
return (T)Enum.ToObject(typeof(T), (int)(object)input & Enum.GetValues(typeof(T)).Cast<int>().Sum());
}

Related

Loop through flag enum while ignoring combined types

I am trying to have a method which fills a list based on the flags set in the enum. My problem is that the iteration through the enum iterates over all elements and not only the elements with one bit set:
using System;
using System.Collections.Generic;
public class Program
{
[Flags]
public enum Modes
{
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
AC = A | C,
All = ~0
}
public class Type
{
public Type(Modes mode){}
}
public static List<Type> Create(Modes modesToCreate = Modes.All)
{
var list = new List<Type>();
foreach(Modes mode in Enum.GetValues(typeof(Modes)))
{
if(modesToCreate.HasFlag(mode))
{
Console.WriteLine(mode);
list.Add(new Type(mode));
}
}
Console.WriteLine();
return list;
}
public static void Main()
{
Create();
Create(Modes.A | Modes.C);
}
}
Real output:
A
B
C
AC
All
A
C
AC
Desired Output:
A
B
C
A
C
How can I ignore the combined flags on the iteration or only iterate over the single bit enum values?
You could use BitOperations.PopCount() to check if the mode has more than one bit set:
public static List<Type> Create(Modes modesToCreate = Modes.All)
{
var list = new List<Type>();
foreach (Modes mode in Enum.GetValues(typeof(Modes)))
{
if (modesToCreate.HasFlag(mode) && BitOperations.PopCount((uint)mode) == 1)
{
Console.WriteLine(mode);
list.Add(new Type(mode));
}
}
Console.WriteLine();
return list;
}
If using .net Framework 4.8 or earlier, you can't use PopCount. In that case, you can count the bits using one of the answers to this question:
How to count the number of set bits in a 32-bit integer?
Alternatively (and probably better) you can just use the well-known bit-twiddle to determine if an integer is a power of two:
(n & (n - 1)) == 0
In which case the code would be:
if (modesToCreate.HasFlag(mode) && (mode & (mode - 1)) == 0)
Although for clarity I'd write that as:
bool isPowerOfTwo = (mode & (mode - 1)) == 0;
if (isPowerOfTwo && modesToCreate.HasFlag(mode))
And as PanagiotisKanavos points out in a comment below, in .net 6.0+ you can use BitOperations.IsPow2():
if (modesToCreate.HasFlag(mode) && BitOperations.IsPow2((uint)mode))

How do you test an enum flag combination?

Let’s say I have an enum flag:
[Flags]
public enum ColorType
{
None = 0,
Red = 1 << 0,
White = 1<<1,
Yellow = 1 << 2,
Blue = 1 << 3,
All = Red | White | Yellow | Blue
}
I have the below function, which parameter is a combination of flag, such as DoSomething( ColorType.Blue | ColorType.Yellow ).
public void DoSomethingr(ColorType theColorTypes)
{
if (theColorTypes.HasFlag(All)) Foo1();
if (theColorTypes.HasFlag(White) && theColorTypes.HasFlag(Red) ) Foo2();
if (!theColorTypes.HasFlag(Blue)) Foo3();
. . .
}
Is there an easy way to test all of possible flag bitwise combination?
[Test]
public void Test1(ColorType.Red | ColorType.Yellow | ColorType.White)
[Test]
public void Test1(ColorType.Red | ColorType.Yellow | ColorType.white | ColorType.Blue)
Thanks
Loop over all the possible values and put it in a TestCaseSource to generate a different test for each enumeration value:
public IEnumerable<ColorType> TestCaseSource
{
get
{
int start = (int)ColorType.None;
int count = (int)ColorType.All - start + 1;
return Enumerable.Range(start, count).Select(i => (ColorType)i);
}
}
[TestCaseSource("TestCaseSource")]
public void Test1(ColorType colorType)
{
// whatever your test is
}
Just my two cents and this could probably be improved to accept 'other' value types as well, but as an alternative when you like extension methods:
public static class EnumExtensions
{
public static bool HasFlags<TEnum>(this TEnum #enum,
TEnum flag,
params TEnum[] flags)
where TEnum : struct
{
var type = typeof(TEnum);
if (!type.IsEnum)
throw new ArgumentException("#enum is not an Enum");
var hasFlagsMethod = type.GetMethod("HasFlag");
var hasFlag = new Func<TEnum, bool>(e =>
{
return (bool)hasFlagsMethod.Invoke(#enum, new object[] { e });
});
// test the first flag argument
if (!hasFlag(flag))
return false;
// test the params flags argument
foreach (var flagValue in flags)
{
if (!hasFlag(flagValue))
return false;
}
return true;
}
}
[Flags]
public enum ColorType
{
None = 0,
Red = 1 << 0,
White = 1 << 1,
Yellow = 1 << 2,
Blue = 1 << 3,
All = Red | White | Yellow | Blue
}
Call it like this:
class Program
{
static void Main(string[] args)
{
var color = ColorType.Red;
Console.WriteLine(color.HasFlags(ColorType.Red)); // true;
Console.WriteLine(color.HasFlags(ColorType.Red, ColorType.Blue)); // false;
color = ColorType.All;
Console.WriteLine(color.HasFlags(ColorType.Red, ColorType.Blue)); // true;
Console.ReadLine();
}
}

Enum flag attribute C#

i'be looked some same topics but havn't find what i'm looking for
I should use flag enum flag atribute and check if my data is in one of the collections of this enum
For example, enum:
[Flags]
private enum MyEnum {
Apple,
Orange,
Tomato,
Potato
Melon,
Watermelon,
Fruit = Apple | Orange,
Vegetable = Tomato | Potato,
Berry = Melon | Watermelon,
}
In the method i should check a input data. How can i do it?
private void Checking(string data){
if(MyEnum.Fruit contains data) MessageBox.Show("Fruit");
if(MyEnum.Vegetable contains data) MessageBox.Show("Vegetables");
if(MyEnum.Berry contains data) MessageBox.Show("Berry");
}
What should be instead of "contains data"?
UPDATE
private void ZZZ(){
Cheching("Apple");
}
First of, you need to manually number your values with the powers-of-2 sequence :
[Flags]
private enum MyEnum
{
None = 0, // often useful
Apple = 1,
Orange = 2,
Tomato = 4,
Potato = 8,
Melon = 16,
Watermelon = 32,
Fruit = Apple | Orange,
Vegetable = Tomato | Potato,
Berry = Melon | Watermelon,
}
The [Flags] attribute is not strictly necessary, it only controls the ToString() behaviour.
And to check whether a string matches your value you'll have to make it an enum first:
private void Checking(string data)
{
MyEnum v = (MyEnum) Enum.Parse(typeof(MyEnum), data);
if((MyEnum.Fruit & v) != 0) MessageBox.Show("It's a Fruit");
...
}
But do note that interchanging between Enum and string like this with Parse() is limited.
In addition to Henk Holterman's solution you may use extension methods:
[Flags]
private enum MyEnum {
None = 0,
Apple = 1,
Orange = 2,
Tomato = 4,
Potato = 8,
Melon = 16,
Watermelon = 32,
Berry = Melon | Watermelon,
Fruit = Apple | Orange,
Vegetable = Potato | Tomato
}
private static class MyEnumExtensions {
public static Boolean IsFruit(this MyEnum value) {
return (value & MyEnum.Fruit) == MyEnum.Fruit;
}
public static Boolean IsVegetable(this MyEnum value) {
return (value & MyEnum.Vegetable) == MyEnum.Vegetable;
}
public static Boolean IsBerry(this MyEnum value) {
return (value & MyEnum.Berry) == MyEnum.Berry;
}
}
...
MyEnum data = ...
if (data.IsBerry()) {
MessageBox.Show("Berry");
}
You also can use the HasFlag-method of the Enum-class. As Henk pointed out will need to assign the values to your enum manually using values of the powers-of-2 sequence.
[Flags]
private enum MyEnum
{
Apple = 1,
Orange = 2,
Tomato = 4,
Potato = 8,
Melon 16,
Watermelon = 32,
Fruit = Apple | Orange,
Vegetable = Tomato | Potato,
Berry = Melon | Watermelon,
}
Then, to check you could use the following method which is working for all composed parts of your enumeration:
void Cheking(string data)
{
// Get the enum value of the string passed to the method
MyEnum myEnumData;
if (Enum.TryParse<MyEnum>(data, out myEnumData))
{
// If the string was a valid enum value iterate over all the value of
// the underlying enum type
var values = Enum.GetValues(typeof(MyEnum)).OfType<MyEnum>();
foreach (var value in values)
{
// If the value is not a power of 2 it is a composed one. If it furthermore
// has the flag passed to the method this is one we searched.
var isPowerOfTwo = (value != 0) && ((value & (value - 1)) == 0);
if (!isPowerOfTwo && value.HasFlag(myEnumData))
{
MessageBox.Show(value.ToString());
}
}
}
// In case an invalid value had been passed to the method
// display an error message.
else
{
MessageBox.Show("Invalid Value");
}
}
Or to write it in a shorter way using LINQ:
var results = Enum.GetValues(typeof(MyEnum))
.OfType<MyEnum>()
.Select(x => new { Value = x, IsPowerOfTwo = (x != 0) && ((x & (x - 1)) == 0) } )
.Where(x => !x.IsPowerOfTwo && x.Value.HasFlag(myEnumData))
.Select(x => x.Value.ToString());
This will give an IEnumerable<string> containing the results. In case that myEnumData has a value of MyEnum.Apple the result will contain just the value "Fruit".
as #Henk Holterman has suggested, you need first to assign values to the enum.
All values should be a power of 2 (and avoid using 0, except for the special case of "None")
It should look something like this:
MyEnum eVal= (MyEnum ) Enum.Parse( typeof(MyEnum), data, true );
if((MyEnum.Fruit & eVal) != 0) MessageBox.Show("Fruit");
You might want to read more about bitwise and boolean algebra.

Loop through bitwise enum values which have just a single bit field

I have multiple flags enums defined in code similar to the following
[Flags]
public enum Colors
{
None = 0,
Red = 1,
Green = 2,
Blue = 4,
Purple = Red | Blue,
Brown = Red | Green,
}
The following code produces the following output
Colors color1 = Colors.Red | Colors.Blue;
Colors color2 = Colors.Purple;
string s1 = color1.ToString(); // Sets s1 to "Purple"
string s2 = color2.ToString(); // Sets s2 to "Purple"
I want a method that outputs the individual bits of a bitwise enum, even if a matching combination is defined.
private void Foo()
{
Colors color1 = Colors.Red | Colors.Blue;
Colors color2 = Colors.Purple;
string s1 = CreateColumnString(color1); // Sets s1 to "Red|Blue"
string s2 = CreateColumnString(color2); // Sets s2 to "Red|Blue"
}
I thought I could loop through all the values of an enum and check if the value is a power of two. But I can't figure out how to get the underlying value of the Enum argument.
private string CreateColumnString(object value)
{
//is this an enum with Flags attribute?
if (value is Enum && value.GetType().GetCustomAttributes(typeof(FlagsAttribute), true).Length > 0)
{
Enum e = (Enum)value;
//Get a list of Enum values set in this flags enum
IEnumerable<Enum> setValues =
Enum.GetValues(value.GetType())
.Cast<Enum>()
.Where(eachEnum => IsPowerOfTwo(eachEnum) && value.HasFlag(eachEnum));
return string.Join("|", setValues);
}
else
{
return value != null ? value.ToString() : string.Empty;
}
return str;
}
private static bool IsPowerOfTwo(Enum e)
{
int x = (int)e; //ERROR cannot convert type 'System.Enum' to 'ulong'
return (x != 0) && ((x & (x - 1)) == 0);
}
There may be better ways of doing this, but this should do what you are looking for:
private static string AsString<T>(this T values)
{
Enum v = (Enum)Convert.ChangeType(values, typeof(Enum));
Array array = Enum.GetValues(typeof(T));
IEnumerable<Enum> setFlags = array
.Cast<Enum>()
.Where(c => v.HasFlag(c) && IsDistinctValue(c));
return values.Equals(default(T))
? default(T).ToString()
: string.Join("|", setFlags.Where(c => Convert.ToInt32(c) != 0).Select(c => c.ToString()));
}
private static bool IsDistinctValue(Enum value)
{
int current = Convert.ToInt32(value) >> 1;
while (current > 0)
{
if ((Convert.ToInt32(value) & current) != 0)
{
return false;
}
current >>= 1;
}
return true;
}
It will essentially list the values for the set flags, except those that "contain" other flags. It figures this out by taking the value that is being tested, decrementing it towards zero and check whether the original value has that decremented value set as a flag. Finally, it will remove the "None" value, unless no flag is set.
Use it like so:
Colors c = Colors.Purple;
Console.WriteLine(c.AsString());
Here's another approach. I figure the more options you have, the better :)
public static class EnumHelpers
{
public static string ToStringExtended<T>(this Enum e)
{
if (!(e.GetType().GetCustomAttributes(typeof(FlagsAttribute), true).Length > 0))
return e.ToString();
List<string> eNames = new List<string>();
foreach (T fish in Enum.GetValues(typeof(T)))
{
Enum num = fish as Enum;
if (e.HasFlag(num) && Convert.ToInt32(fish) != 0 && Convert.ToInt32(fish) != Convert.ToInt32(e))
eNames.Add(fish.ToString());
}
return eNames.Count > 1 ? String.Join("|", eNames.ToArray()) : e.ToString();
}
}
The usage is almost identical to what Fredirk proposed:
Colors c = Colors.Purple;
Console.WriteLine(c.ToStringExtended<Colors>());
// Output : Red|Blue
You can use the HasFlag method:
.Where(e.HasFlag)
However, I think that your Enum.GetValues call will also get the multi-bit values that your enum type names.
EDIT:
Here's another approach that you might get to work:
if (Enum.GetUnderlyingType(e.GetType()) != typeof(int))
throw new NotImplementedException();
var list = new List<Enum>();
for (int i = 1; i != 0; i <<= 1)
{
var eachEnum = (Enum)(Enum.ToObject(e.GetType(), i));
if (e.HasFlag(eachEnum))
list.Add(eachEnum);
}
return string.Join(" | ", list);
An answer in 4 lines of code not counting the method signature.
private static string CreateColumnString(Colors value)
{
// This is how we do it in embedded programming in C
// In C we wouldn't need to convert, but alas in C# we do
// So first ...
var num = Convert.ToByte(value);
// ToUint16 would work as well, but ToByte makes your intentions clearer
// Then bitwise '& 'every bit position you care about to compose your string
// For example: 0b0011 & 0b1111 = 0b0011 (3 AND 15 = 3)
var s = (num & 1) > 0 ? "Red" : "";
s = (num & 2) > 0 ? s + "|Green": s;
return (num & 2) > 0 ? s + "|Blue" : s;
}

How to get next (or previous) enum value in C#

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 next one which is eRat.C
The solution I see is (without range checking)
Array a = Enum.GetValues(typeof(eRat));
int i=0 ;
for (i = 0; i < a.GetLength(); i++)
{
if (a.GetValue(i) == eRat.B)
break;
}
return (eRat)a.GetValue(i+1):
Now that is too much complexity, for something that simple. Do you know any better solution?? Something like eRat.B+1 or Enum.Next(Erat.B)?
Thanks
Thanks to everybody for your answers and feedback. I was surprised to get so many of them. Looking at them and using some of the ideas, I came up with this solution, which works best for me:
public static class Extensions
{
public static T Next<T>(this T src) where T : struct
{
if (!typeof(T).IsEnum) throw new ArgumentException(String.Format("Argument {0} is not an Enum", typeof(T).FullName));
T[] Arr = (T[])Enum.GetValues(src.GetType());
int j = Array.IndexOf<T>(Arr, src) + 1;
return (Arr.Length==j) ? Arr[0] : Arr[j];
}
}
The beauty of this approach, that it is simple and universal to use. Implemented as generic extension method, you can call it on any enum this way:
return eRat.B.Next();
Notice, I am using generalized extension method, thus I don't need to specify type upon call, just .Next().
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;
}
}
The problem you're dealing with is because you're trying to get an enum to do something it shouldn't. They're supposed to be type safe. Assigning integral values to an enum is allowed so that you can combine them, but if you want them to represent integral values, use classes or structs. Here's a possible alternative:
public static class eRat
{
public static readonly eRatValue A;
public static readonly eRatValue B;
public static readonly eRatValue C;
public static readonly eRatValue D;
static eRat()
{
D = new eRatValue(8, null);
C = new eRatValue(5, D);
B = new eRatValue(3, C);
A = new eRatValue(0, B);
}
#region Nested type: ERatValue
public class eRatValue
{
private readonly eRatValue next;
private readonly int value;
public eRatValue(int value, eRatValue next)
{
this.value = value;
this.next = next;
}
public int Value
{
get { return value; }
}
public eRatValue Next
{
get { return next; }
}
public static implicit operator int(eRatValue eRatValue)
{
return eRatValue.Value;
}
}
#endregion
}
This allows you to do this:
int something = eRat.A + eRat.B;
and this
eRat.eRatValue current = eRat.A;
while (current != null)
{
Console.WriteLine(current.Value);
current = current.Next;
}
You really should only be using enums when you can benefit from their type safety. If you're relying on them to represent a type, switch to constants or to classes.
EDIT
I would suggest you take a look at the MSDN page on Enumeration Design. The first best practice is:
Do use an enumeration to strongly type
parameters, properties, and return
values that represent sets of values.
I try not to argue dogma, so I won't, but here's the problem you're going to face. Microsoft doesn't want you to do what you are trying to do. They explicitly ask you not to do what you are trying to do. The make it hard for you to do what you are trying to do. In order to accomplish what you are trying to do, you have to build utility code to force it to appear to work.
You have called your solution elegant more than once, and it might be if enums were designed in a different way, but since enums are what they are, your solution isn't elegant. I think that chamber music is elegant, but if the musicians didn't have the proper instruments and had to play Vivaldi with sawblades and jugs, it would no longer be elegant, regardless of how capable they were as musicians, or how good the music was on paper.
Works up to "C" since there is no answer on what to return after "D".
[update1]: Updated according to Marc Gravell's suggestion.
[update2]: Updated according to how husayt's wanted - return "A" for the next value of "D".
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Next enum of A = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.A));
Console.WriteLine("Next enum of B = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.B));
Console.WriteLine("Next enum of C = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.C));
}
}
public enum eRat { A = 0, B = 3, C = 5, D = 8 };
public class eRatEnumHelper
{
public static eRat GetNextEnumValueOf(eRat value)
{
return (from eRat val in Enum.GetValues(typeof (eRat))
where val > value
orderby val
select val).DefaultIfEmpty().First();
}
}
Result
Next enum of A = B
Next enum of B = C
Next enum of C = D
Next enum of D = A
Thanks you all, for your inspiration and solutions.
Here are my results, as an extension.
using System;
using System.Linq;
public static class Enums
{
public static T Next<T>(this T v) where T : struct
{
return Enum.GetValues(v.GetType()).Cast<T>().Concat(new[] { default(T) }).SkipWhile(e => !v.Equals(e)).Skip(1).First();
}
public static T Previous<T>(this T v) where T : struct
{
return Enum.GetValues(v.GetType()).Cast<T>().Concat(new[] { default(T) }).Reverse().SkipWhile(e => !v.Equals(e)).Skip(1).First();
}
}
use:
using System;
using System.Linq;
public enum Test { F1, F2, F3 }
public class Program
{
public static void Main()
{
Test t = Test.F3;
Console.WriteLine(t);
Console.WriteLine(t.Next());
Console.WriteLine(t.Previous());
Console.WriteLine("\n");
t = Test.F1;
Console.WriteLine(t);
Console.WriteLine(t.Next());
Console.WriteLine(t.Previous());
}
}
result:
F3
F1
F2
F1
F2
F3
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.
For simple solution, you might just extract array from enum.
eRat[] list = (eRat[])Enum.GetValues(typeof(eRat));
Then you can enumerate
foreach (eRat item in list)
//Do something
Or find next item
int index = Array.IndexOf<eRat>(list, eRat.B);
eRat nextItem = list[index + 1];
Storing the array is better than extracting from enum each time you want next value.
But if you want more beautiful solution, create the class.
public class EnumEnumerator<T> : IEnumerator<T>, IEnumerable<T> {
int _index;
T[] _list;
public EnumEnumerator() {
if (!typeof(T).IsEnum)
throw new NotSupportedException();
_list = (T[])Enum.GetValues(typeof(T));
}
public T Current {
get { return _list[_index]; }
}
public bool MoveNext() {
if (_index + 1 >= _list.Length)
return false;
_index++;
return true;
}
public bool MovePrevious() {
if (_index <= 0)
return false;
_index--;
return true;
}
public bool Seek(T item) {
int i = Array.IndexOf<T>(_list, item);
if (i >= 0) {
_index = i;
return true;
} else
return false;
}
public void Reset() {
_index = 0;
}
public IEnumerator<T> GetEnumerator() {
return ((IEnumerable<T>)_list).GetEnumerator();
}
void IDisposable.Dispose() { }
object System.Collections.IEnumerator.Current {
get { return Current; }
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return _list.GetEnumerator();
}
}
Instantiate
var eRatEnum = new EnumEnumerator<eRat>();
Iterate
foreach (eRat item in eRatEnum)
//Do something
MoveNext
eRatEnum.Seek(eRat.B);
eRatEnum.MoveNext();
eRat nextItem = eRatEnum.Current;
Judging from your description, you don't really want an enum. You're stretching enum beyond its capabilities. Why not create a custom class that exposes the values you need as properties, while keeping them in OrderedDictionary.
Then getting a next/previous one would be trivial.
--update
If you want to enumerate differently on the collection based in the context, make that explicit part of your design.
Encapsulate the items within a class, and have few methods each returning IEnumerable where, T is your desired type.
For example
IEnumerable<Foo> GetFoosByBar()
IEnumerable<Foo> GetFoosByBaz()
etc...
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.
Hope this part of my code helps you:
public enum EGroupedBy
{
Type,
InterfaceAndType,
Alpha,
_max
}
private void _btnViewUnit_Click(object sender, EventArgs e)
{
int i = (int)GroupedBy;
i = (i + 1) % (int)EGroupedBy._max;
GroupedBy = (EGroupedBy) i;
RefreshUnit();
}
Old post, but I have an alternative solution
//Next with looping
public static Enum Next(this Enum input)
{
Array Arr = Enum.GetValues(input.GetType());
int j = Array.IndexOf(Arr, input) + 1;
return (Arr.Length == j) ? (Enum)Arr.GetValue(0) : (Enum)Arr.GetValue(j);
}
//Previous with looping
public static Enum Prev(this Enum input)
{
Array Arr = Enum.GetValues(input.GetType());
int j = Array.IndexOf(Arr, input) - 1;
return (j == -1) ? (Enum)Arr.GetValue(Arr.Length -1) : (Enum)Arr.GetValue(j);
}
And when you need to use it, just do a cast
BootstrapThemeEnum theme = BootstrapThemeEnum.Info;
var next = (BootstrapThemeEnum)theme.Next();
my enum
public enum BootstrapThemeEnum
{
[Description("white")]
White = 0,
[Description("default")]
Default = 1,
[Description("info")]
Info = 2,
[Description("primary")]
Primary = 3,
[Description("success")]
Success = 4,
[Description("warning")]
Warning = 5,
[Description("danger")]
Danger = 6,
[Description("inverse")]
Inverse = 7
}
I can think of 2 things:
eRat.B+3
Enum.Parse(typeof(((int)eRat.B)+3)
var next = (eRat)((int)someRat + 3);
Seems like an abuse of the enum class to me - but this would do it (assuming that calling Next on the last value would cause wrap-around):
public static eRat Next(this eRat target)
{
var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().SkipWhile(e => e != target).Skip(1);
if (nextValueQuery.Count() != 0)
{
return (eRat)nextValueQuery.First();
}
else
{
return eRat.A;
}
}
And this would give you the previous value on the same basis:
public static eRat Previous(this eRat target)
{
var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().Reverse().SkipWhile(e => e != target).Skip(1);
if (nextValueQuery.Count() != 0)
{
return (eRat)nextValueQuery.First();
}
else
{
return eRat.D;
}
}
I'm using this, perfect for my.
//===================================================================================
// NEXT VALUE IN ENUM
// ex: E_CamModes eNew = kGlobalsVars.eGetNextValue< E_CamModes >( geCmMode );
public static T eGetNextValue< T >( T eIn ){
T[] aiAllValues = ( T[] ) Enum.GetValues( typeof( T ));
int iVal = System.Array.IndexOf( aiAllValues, eIn );
return aiAllValues[ ( iVal + 1 ) % aiAllValues.Length ];
}
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
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 :)
From comments I had many question like: "Why would you ever want to use enum in this way." Since so many of you asked, let me give you my use case and see if you agree then:
I have a fixed array of items int[n]. Depending on the situation I want to enumerate through this array differently. So i defined:
int[] Arr= {1,2,34,5,6,78,9,90,30};
enum eRat1 { A = 0, B=3, C=5, D=8 };
enum eRat2 { A, AA,AAA,B,BB,C,C,CC,D };
void walk(Type enumType)
{
foreach (Type t in Enum.GetValues(enumType))
{
write(t.ToString() + " = " + Arr[(int)t)];
}
}
and call walk(typeof(eRAt1)) or walk(typeof(eRAt2))
then i get required output
1) walk(typeof(eRAt1))
A = 1
B = 5
C = 78
D = 30
2) walk(typeof(eRAt2))
A = 1
AA = 2
AAA = 34
B = 5
BB = 6
C = 78
CC = 90
D = 30
This is very simplified. But i hope, this explains. There are some other advantages to this, as having enum.toString(). So basically i use enums as indexers.
So using the solution I can do something like this now.
In sequence eRat1 next value to B is C, but in eRat2 it is BB.
So depending on which sequence I am interested in, I can do e.next and depending on enumType I will either get C or BB. How would one achieve that with dictionaries?
I think this a rather elegant use of enums.
I'm using this here:
public MyEnum getNext() {
return this.ordinal() < MyEnum.values().length - 1 ?
MyEnum.values()[this.ordinal() + 1] :
MyEnum.values()[0];
}
LINQ solution that does not break on last element but continues at the default again:
var nextValue = Enum.GetValues(typeof(EnumT)).Cast<EnumT>().Concat(new[]{default(EnumT)}).SkipWhile(_ => _ != value).Skip(1).First();
I tried the first solution but it did not work for me. Below is my solution:
public object NextEnumItem(object currentEnumItem)
{
if (!currentEnumItem.GetType().IsEnum) throw new
ArgumentException(String.Format("Argument is not an Enum"));
Array Arr = Enum.GetValues(currentEnumItem.GetType());
int j = Array.IndexOf(Arr,currentEnumItem) + 1;
return (Arr.Length == j) ? currentEnumItem : Arr.GetValue(j);
}
public object PreviousEnumItem(object currentEnumItem)
{
if (!currentEnumItem.GetType().IsEnum)
throw new ArgumentException(String.Format("Argument is not an Enum"));
Array Arr = Enum.GetValues(currentEnumItem.GetType());
int j = Array.IndexOf(Arr, currentEnumItem) - 1;
return (j==-1) ? currentEnumItem : Arr.GetValue(j);
}
I did something similar with a different enum. It's for a game and the player has the chance to toggle colors.
public enum PlayerColor {
Red = 0, Green, Blue, Cyan, Yellow, Orange, Purple, Magenta
}
public PlayerColor GetNextFreeColor(PlayerColor oldColor) {
PlayerColor newColor = (PlayerColor)((int)(oldColor + 1) % 8);
return newColor;
}
This solution worked for me.
Based on best answer from Yahya Hussein here is edit of his code for Previous element in Enum
public static class Extensions
{
public static T Previous<T>(this T src) where T : struct
{
if (!typeof(T).IsEnum) throw new ArgumentException(String.Format("Argument {0} is not an Enum", typeof(T).FullName));
T[] Arr = (T[])Enum.GetValues(src.GetType());
int j = Array.IndexOf<T>(Arr, src) - 1;
return (j < 0) ? Arr[Array.Length - 1] : Arr[j];
}
}
enum Level
{
Easy,
Medium,
Expert
};
public static void Main()
{
var difficulty = Level.Easy;
var level = (int)difficulty;
Console.WriteLine(difficulty);
Console.WriteLine(level);
Console.WriteLine("promote level");
level++;
Console.WriteLine(level);
difficulty = (Level)level;
Console.WriteLine(difficulty);
}
You can add and remove integers to an enum to obtain the next value. The only problem is that integer operations on the enum will not check the validity of the enum itself, thus could set "invalid" values.
But you can combine the ++enum and the Enum.IsDefined() to obtain a simple way to get next and previous values of your enum. This would be inefficient in your case since the integer values are not continuous, but if you have continuous integers then it works nicely, and one can check when the ++enum is out of range. Check the next example.
public enum level
{
a = 0,
b = 1,
c = 2,
d = 3,
e = 4
}
private static void Main(string[] args)
{
var levelValue = level.a;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(levelValue);
++levelValue;
Console.WriteLine(Enum.IsDefined(typeof(Program.level), levelValue));
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(Enum.IsDefined(typeof(Program.level), levelValue));
Console.WriteLine(levelValue);
--levelValue;
Console.WriteLine(Enum.IsDefined(typeof(Program.level), levelValue));
Console.WriteLine(levelValue);
}
The output for this would be:
a
b
c
d
e
False
5
e
d
c
b
True
a
False
-1

Categories