Reputation: 5226
Let's say I have this enum:
[Flags]
public enum SomeType
{
Val1 = 0,
Val2 = 1,
Val3 = 2,
Val4 = 4,
Val5 = 8,
Val6 = 16,
All = Val1 | Val2 | Val3 | Val4 | Val5 | Val6
}
and some variables:
SomeType easyType = SomeType.Val1 | SomeType.Val2;
SomeType complexType = SomeType.All;
If I want to loop through values of the first enum I can simply do:
foreach(string s in easyType.ToString().Split(','))
{ ... }
However, when I try to apply the same approach to the 'complexType' I get value 'All', which is of course valid because it's also one of possible values of the enum. But, is there a neat way to actually see of what values is the SomeType.All created of? I know I could make a manual loop through all the values like that:
if(complexType.HasFlag(ManualType.Val1) && ...
Upvotes: 10
Views: 1840
Reputation: 34200
If you're using an enum to represent data that has some deeper level of complexity (arbitrary groups of elements, "darkness" of colour, etc.) and struggling because of that, I'd suggest that an enum is the wrong programming construct to be using.
Using an enum for these tasks will always be error prone: if I add a new colour to your enum, I have to remember to add it to "Bright" or "Dark" too. That makes your code just as error prone for developers as the original problem. What you could do, however, is define a class
or struct
for colour that has a property indicating whether it's bright or not. Then you'll have clear, understandable functionality - implemented in a way that doesn't give spurious results as when you're trying to misuse a simpler language feature.
That, for example, is why Color
is a struct
...
Upvotes: 0
Reputation: 38106
Here's one possible way to do it, building on Danny Chen's answer:
public IEnumerable<T> GetFlags<T>(Predicate<int> hasFlag)
{
return GetEnumFlags<T>().Where(f => hasFlag(f)).Cast<T>();
}
private IEnumerable<int> GetEnumFlags<T>()
{
return Enum.GetValues(typeof(T)).Cast<int>().Where(IsPowerOfTwoOrZero);
}
private bool IsPowerOfTwoOrZero(int v)
{
return ((v & (v-1)) == 0);
}
Usage:
void Main()
{
SomeType easyType = SomeType.Val1 | SomeType.Val2;
SomeType complexType = SomeType.All;
GetFlags<SomeType>(v => easyType.HasFlag((SomeType)v));
GetFlags<SomeType>(v => complexType.HasFlag((SomeType)v));
}
Note this will work for Enums based on types castable to int
. You can create similar methods for long
etc.
Upvotes: 0
Reputation: 43513
var result = string.Join(",",
Enum.GetValues(typeof(SomeType))
.Cast<SomeType>()
.Where(v => complexType.HasFlag(v)));
You can write an extension method to avoid repeating yourself.
Upvotes: 4
Reputation: 71060
Maybe you need to enumerate the enum values and test each one:
foreach (SomeType item in Enum.GetValues (typeof (SomeType))
{
if ((complexType & item) == item)
{
//...
}
}
Upvotes: 0