0

The Enum class has the following useful function:

public static Array GetValues(Type enumType);

How could I write something similar to give me a collection of all an enum instance's set bits? With a signature like:

public static IEnumerable<T> getFlagValues<T>(this Enum enum, T enumInstance) where T : struct;

I am having trouble getting the casting to work, as I'm not allowed to constrain by Enum so I need to use struct.

Bobby B
  • 2,287
  • 2
  • 24
  • 47

2 Answers2

2

I think that you mean like this:

public static IEnumerable<T> getFlagValues<T>(this T enumValue) where T : struct {
  foreach (object o in Enum.GetValues(typeof(T))) {
    if (((int)o & (int)(object)enumValue) != 0) yield return (T)o;
  }
}

You only need one parameter, as you would call it on the enum value. Example:

[Flags]
public enum X { a = 1, b = 2, c = 4 }

X x = X.a | X.c;

foreach (var n in x.getFlagValues()) {
  Console.WriteLine(n);
}

Output:

a
c
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • 1
    +1. Note that if enum contains more than just single bit values (i.e. `Mask = Value1|Value2`) than such value will be returned too. If only single bit values are required than some form of filtering enum on number of bits set per value is needed. – Alexei Levenkov Mar 04 '13 at 02:25
  • @AlexeiLevenkov: Yes, good point. This returns the values where some of the bits match. You can compare with the exact value instead of checking for non-zero values, then it only returns values where all bits match. – Guffa Mar 04 '13 at 10:05
  • @Guffa what do you mean compare against exact value? – Bobby B Mar 04 '13 at 14:21
  • @BobbyB: `if (((int)o & (int)(object)enumValue) == (int)o` – Guffa Mar 04 '13 at 15:02
  • @Guffa problem is when it checks the `0` value (if the enum has such a value, which it could), it will always be included even if not in your input value, as `0 & whatever == 0`, so I'd like to solve this mask problem, but not sure how? – Bobby B Mar 04 '13 at 17:24
  • @BobbyB: Yes, if you have an enum value that represents zero bits that would also be included. By definition, the mask with zero bits will always be matched by any bit pattern. If you want to excluded that value, you can simply add an `if ((int)o != 0)` in the loop. – Guffa Mar 04 '13 at 17:30
  • @Guffa true, except for most enums that would be an acceptable value ;) – Bobby B Mar 04 '13 at 17:32
  • @BobbyB: There is no way for the code to magically know for which enums you want the zero value to always be included. You would need to add another parameter to the call to tell it how it should behave. – Guffa Mar 04 '13 at 17:36
  • @Guffa yes you're right of course, so only options are not to have a zero value in the enum (but can't often dictate that if its code by contract), or, argument to function like "bool ignoreZero". – Bobby B Mar 04 '13 at 17:48
  • @BobbyB: Yes, it's easy to create an `enum` that gives odd results when used with bit flags. Also you can create an `enum` value from any numeric value, that has bits set not represented by the defined values, and thus would not return a value for each bit set. – Guffa Mar 04 '13 at 19:07
1

This may work for your situation

public static IEnumerable<T> GetFlagValues<T>(this T enumValue) where T : struct
{
    return Enum.GetValues(typeof(T)).Cast<Enum>().Where(e => ((Enum)(object)enumValue).HasFlag(e)).Cast<T>();
}

Test

[Flags]
public enum TestEnum
{
    One = 1,
    Two = 2,
    Three = 3
}

TestEnum test = TestEnum.One | TestEnum.Three;
var result = test.GetFlagValues();

Returns

One
Three
One | Three
sa_ddam213
  • 42,848
  • 7
  • 101
  • 110
  • I think this is the better answer but I would change your example enum to be a more realistic example per @Aron's comment. – Jeff Nov 27 '14 at 22:43