How to get complex enum value string representation
Asked Answered
P

4

10

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) && ...
Poisoning answered 11/2, 2011 at 11:57 Comment(8)
I think the problem is that you shouldn't put All inside this enum. Since you mark it [Flags], it's a bad idea to put any combination in it.Ganley
Then I (and others) will have to always remember to use proper combination of enums when using SomeType for something.Poisoning
Can you post the original enum instead of pointless SomeType?Ganley
It's not useless. To make it more readable let's use an example of Colours. Define 10 colours and just divide them into 2 subsets - bright and dark ones. Does that answers you? If I will not use additional DarkColours enum value I will have to always send 5 values at the same time. Error prone to me.Poisoning
And what you want? Splited string presentation of a SomeType?Ganley
You are correct. I didn't mean put All inside an enum is always useless. What I'm going to say is perhaps it's not useful in your code? That's why I want to know your original enum, not SomeType.Ganley
indeed, I want to get splitted string representation of SomeType.AllPoisoning
Please consider renaming this question. The word "disassemble" is misleading in the title and will make people think you want to view the disassembled IL of the enum.Parabasis
G
4
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.

Ganley answered 11/2, 2011 at 12:41 Comment(4)
Won't this also include ", All" at the end? Does that need a special case to ignore it?Contingency
@Justin: Yes it will. But what can we do? Check if it's "All"? What if its name is "AllOptions"? So we can't deal with this "special case".Ganley
The only option I can think of is to keep a running bitwise-OR of all the previous values seen, and then ignore a value if it does not contain any new bits. It would be dependent on the order, though.Contingency
great code! And adding ".Except(new SomeType[]{ SomeType.All}));" right after "Where" will do the job. Thanks, now it's quite smooth!Poisoning
G
0

Maybe you need to enumerate the enum values and test each one:

foreach (SomeType item in Enum.GetValues (typeof (SomeType))
{
  if ((complexType & item) == item)
  {
    //...
  }
}
Guadalupe answered 11/2, 2011 at 12:1 Comment(1)
But then I will test for All also. It's ok in my situation, but what if I would have defined also SomeType.JustThree = Val1|Val2|Val3. It's redundant at least.Poisoning
D
0

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.

Dahabeah answered 11/2, 2011 at 13:42 Comment(0)
G
0

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

Geest answered 11/2, 2011 at 14:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.