Question

I spent a couple hours trying to figure out a generic way of converting an Enum mask to an array of Enum values and, conversely, an array of Enum values to its Enum mask.

Writing an extension method to do so was a bit of a pain so I just wanted to share my solution in case it could help someone. I'm sure it could be improved but, here it is!

No correct solution

OTHER TIPS

The extension method below returns a mask from a list of Enum values.

public static T ToMask<T>(this IEnumerable<T> values) where T : struct, IConvertible
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("T must be an enumerated type.");

     int builtValue = 0;
     foreach (T value in Enum.GetValues(typeof(T)))
     {
        if (values.Contains(value))
        {
            builtValue |= Convert.ToInt32(value);
        }
    }
    return (T)Enum.Parse(typeof(T), builtValue.ToString());
}

The extension method below returns a list of Enum values from a mask.

public static IEnumerable<T> ToValues<T>(this T flags) where T : struct, IConvertible
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("T must be an enumerated type.");

    int inputInt = (int)(object)(T)flags;
    foreach (T value in Enum.GetValues(typeof(T)))
    {
        int valueInt = (int)(object)(T)value;
        if (0 != (valueInt & inputInt))
        {
            yield return value;
        }
    }
}

Note that:

  1. Generic constraints in c# (where T : ...) cannot restrict T to an Enum
  2. These methods do not check whether the Enum has the [Flags] attribute (could not figure that out)

Usage:

[Flags]
public enum TestEnum : int
{
    None = 0,
    Plop = 1,
    Pouet = 2,
    Foo = 4,
    Bar = 8
}

To mask:

TestEnum[] enums = new[] { TestEnum.None, TestEnum.Plop, TestEnum.Foo };
TestEnum flags = enums.ToMask();

TestEnum expectedFlags = TestEnum.None | TestEnum.Plop | TestEnum.Foo;
Assert.AreEqual(expectedFlags, flags);

To values:

TestEnum flags = TestEnum.None | TestEnum.Plop | TestEnum.Foo;
TestEnum[] array = flags.ToValues().ToArray();

TestEnum[] expectedArray = new[] { TestEnum.Plop, TestEnum.Foo };
CollectionAssert.AreEqual(expectedArray, array);

I needed a simple solution for converting the opposite direction (instead of having to include the extension), so here's a Linq solution to turn an IEnumerable of your enum into a flagged enum:

MyEnum e = MyEnumList.Aggregate((MyEnum)0, (a,b) => a |= b);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top