Search code examples
c#enumsflags

Printing Flags Enum as Separate Flags


I have a flags enum defined like this:

[Flags]
public enum MyEnum
{
    None =     0x00,
    Choice1 =  0x01,
    Choice2 =  0x02,
    Choice3 =  0x04,
    Default =  Choice1 | Choice2,
    All =      Default | Choice3
}

I would like a way to print out which flags are included in MyEnum.Default. In this case, I'd want the output to be something like "Choice1, Choice2".

The problem with simply printing MyEnum.Default.ToString() is that the output would be "Default" when I want "Choice1, Choice2".

Here's one option, but if I used this I'd have to update the printing every time I changed the enum.

((StudyData.Choice1 & StudyData.Default) == StudyData.Choice1 ? StudyData.Choice1.ToString() : "") + ", " +
((StudyData.Choice2 & StudyData.Default) == StudyData.Choice2 ? StudyData.Choice2.ToString() : "") + ", " +
((StudyData.Choice3 & StudyData.Default) == StudyData.Choice3 ? StudyData.Choice3.ToString() : "")

Does anyone have a cleaner way of doing this? Ideally, I'd like a way of printing out the flags included in MyEnum.Default without having to change the printing code every time I added a new flag or changed the default.

Thanks!


Solution

  • Using the extension methods I've written here on a related question, this should be simple:

    var value = MyEnum.Default;
    var str = String.Join(", ", value.GetIndividualFlags());
    // "Choice1, Choice2"
    

    And here's the extension methods:

    static class EnumExtensions
    {
        public static IEnumerable<Enum> GetFlags(this Enum value)
        {
            return GetFlags(value, Enum.GetValues(value.GetType()).Cast<Enum>().ToArray());
        }
    
        public static IEnumerable<Enum> GetIndividualFlags(this Enum value)
        {
            return GetFlags(value, GetFlagValues(value.GetType()).ToArray());
        }
    
        private static IEnumerable<Enum> GetFlags(Enum value, Enum[] values)
        {
            ulong bits = Convert.ToUInt64(value);
            List<Enum> results = new List<Enum>();
            for (int i = values.Length - 1; i >= 0; i--)
            {
                ulong mask = Convert.ToUInt64(values[i]);
                if (i == 0 && mask == 0L)
                    break;
                if ((bits & mask) == mask)
                {
                    results.Add(values[i]);
                    bits -= mask;
                }
            }
            if (bits != 0L)
                return Enumerable.Empty<Enum>();
            if (Convert.ToUInt64(value) != 0L)
                return results.Reverse<Enum>();
            if (bits == Convert.ToUInt64(value) && values.Length > 0 && Convert.ToUInt64(values[0]) == 0L)
                return values.Take(1);
            return Enumerable.Empty<Enum>();
        }
    
        private static IEnumerable<Enum> GetFlagValues(Type enumType)
        {
            ulong flag = 0x1;
            foreach (var value in Enum.GetValues(enumType).Cast<Enum>())
            {
                ulong bits = Convert.ToUInt64(value);
                if (bits == 0L)
                    //yield return value;
                    continue; // skip the zero value
                while (flag < bits) flag <<= 1;
                if (flag == bits)
                    yield return value;
            }
        }
    }