2

I have defined an enum with the [Flag] attribute.

Given an integer value, I would like to print all the enum values for the bits set in the integer value.

Here's what I have so far.

string s = string.Join(", ", Enum.GetValues(typeof(MyEnumType)).OfType<Enum>()
                                 .Where(x => (MyIntValue & (int)x) != 0));

But the typecast to int in the last line gives me the following error.

Cannot convert type 'System.Enum' to 'int'

I wish Microsoft would replace all the Framework code that returns Array in favor of types that support LINQ.

But is there an easy way to do this?

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • 1
    Why don't do `.OfType()` instead of `.OfType()`? – Yacoub Massad May 12 '16 at 19:40
  • casting your int value to the Enum and calling ToString() should do exactly what you want. See http://stackoverflow.com/questions/8447/what-does-the-flags-enum-attribute-mean-in-c?rq=1 – devio May 12 '16 at 19:48
  • "I wish Microsoft would replace all the Framework code that returns Array in favor of types that support LINQ." - and what should they do about all of the legacy code that was written before Linq? Just let all that code developed over the years suddenly break? – D Stanley May 12 '16 at 19:49
  • BTW, Arrays support Linq just fine as they implement `IEnumerable` as well as `IEnumerable`. – D Stanley May 12 '16 at 19:51
  • @DStanley Uh, Microsoft updates the Framework all the time. They can do it so it doesn't break code. Create a new class to do the work. There are endless ways. Why would you assume I am asking Microsoft to break all the existing code? – Jonathan Wood May 12 '16 at 20:06
  • @DStanley `System.Array` doesn't implement `IEnumerable`. – Jonathan Wood May 12 '16 at 20:07
  • @JonathanWood Sorry, I thought you were talking about arrays like `int[]`. I stand corrected. – D Stanley May 12 '16 at 20:10

3 Answers3

4

Casting to MyEnumType instead of the generic Enum should fix the problem:

string s = string.Join(
    ", ",
    Enum.GetValues(typeof(MyEnumType))
        .OfType<MyEnumType>()
        .Where(x => (MyIntValue & (int)x) != 0));

You should really be using Cast instead of OfType since you are sure that the items are of type MyEnumType.

Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62
  • Yeah, you're right. This code is still too messy and executes too slow. Microsoft needs to update the Framework. Thanks. – Jonathan Wood May 12 '16 at 19:45
  • @JonathanWood Which part executes "too slow" and how do you propose that Microsoft fix it? – D Stanley May 12 '16 at 19:52
  • I read `OfType()` can impact performance. What if `Enum.GetValues()` returned `List`, where `T` was my enum type? That would be so much more natural, particularly when using LINQ. The problem is that these routines were written before generics. That's why I think they should be rewritten. – Jonathan Wood May 12 '16 at 20:05
  • 1
    I think `Cast` should be slightly faster because it doesn't filter (and filtering isn't necessary). But what is slow? Does the enum type have so many values that this becomes noticeably slow? – Gert Arnold May 12 '16 at 20:23
3

Too much LINQ way of thinking, so sometimes we forget where we come from:) Starting from the very first .NET version, Enum.GetValues(typeof(MyEnum)) actually returns MyEnum[], so what you need is neither OfType, nor Cast, but simple C# cast:

string s = string.Join(", ", ((MyEnum[])Enum.GetValues(typeof(MyEnumType)))
    .Where(x => (MyIntValue & (int)x) != 0));

Since that typeof combined with the casting to the same type is quite annoying, from a very long time I have this little helper in my pocket:

public static class EnumInfo
{
    public static T[] GetValues<T>() where T : struct // I (and not only) wish I could say where T : enum
    {
        return (T[])Enum.GetValues(typeof(T));
    }
}

which allows me to use much more concise

string s = string.Join(", ", EnumInfo.GetValues<MyEnumType>()
    .Where(x => (MyIntValue & (int)x) != 0));
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
1

You can write your own GetValues method that uses generics to get what you need:

public static class EnumUtil
{
    public static IEnumerable<T> GetValues<T>()
    {
        foreach(T enumVal in Enum.GetValues(typeof(T)))
        {
            yield return enumVal;
        }
    }
} 

Which is then used like so:

var s = string.Join(", ", EnumUtil.GetValues<TestEnum>()
    .Where(x => (myIntValue & (int)x) != 0));
esmoore68
  • 1,276
  • 1
  • 8
  • 16