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!
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:
where T : ...
) cannot restrict T to an Enum[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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With