I solved this in the shortest, most understandable code, which, as I expect, works well, although there is boxing in several places. Using your type as an example:
MyEnum e = MyEnum.Choice1 | MyEnum.Choice2; string s = FlagsEnumToString<MyEnum>(e);
Here's how it is implemented:
const string Separator = ", "; public static string FlagsEnumToString<T>(Enum e) { var str = new StringBuilder(); foreach (object i in Enum.GetValues(typeof(T))) { if (IsExactlyOneBitSet((int) i) && e.HasFlag((Enum) i)) { str.Append((T) i + Separator); } } if (str.Length > 0) { str.Length -= Separator.Length; } return str.ToString(); } static bool IsExactlyOneBitSet(int i) { return i != 0 && (i & (i - 1)) == 0; }
Some comments may arise, and I will consider them first of all:
Do I need to call your method providing both a type and a variable?
Because it is impossible to do with the general argument T implicitly. T cannot be used for Enum for HasFlag . No, also not using where T : struct, IConvertible .
foreach also use object ?
Yes, also to be able to throw. Only object can be passed to other types of T , int , Enum .
I think this can be optimized by casting to int inside the loop once with a temporary variable.
I think yes. This code was written like this for clarity. So yes, do it and get rid of these HasFlag calls if you want.
I think you can still use Enum as a foreach variable and save when casting.
No, because you need to make the T tag, and this can only be done from object . There may be βbestβ solutions, but this is by far the shortest and clearest.