Printing flags as separate flags

I have a flag enumeration defined as follows:

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

I need a way to print which flags are included in MyEnum.Default . In this case, I want the result to be something like "Choice1, Choice2".

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

There is one parameter, but if I used this, I would have to update the print every time I changed the enumeration.

 ((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 to do this? Ideally, I would like to print the flags included in MyEnum.Default without having to change the print code every time I add a new flag or change the default value.

Thanks!

+9
source share
6 answers

Using the extension methods that I wrote here on the relevant question, this should be simple:

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

And here are 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; } } } 
+14
source

Decorate your listing with FlagsAttribute . This does exactly what you are looking for:

 [Flags] public enum FooNum { foo = 0, bar = 1, lulz = 2, borkbork = 4 } FooNum f = FooNum.bar | FooNum.borkbork; Debug.WriteLine(f.ToString()); 

should give you:

bar, borkbork

+4
source
 using System; using System.Collections.Generic; using System.Text; namespace printStar { class Program { static void Main(string[] args) { Console.WriteLine("Enter the value "); int k = int.Parse(Console.ReadLine()); int n = k - 1; int x = 2 * (k - 1) + 1; for (int p = 0; p <= n; p++) { for (int j = k - 1; j >= 0; j--) { Console.Write(" "); } for (int i = 0; i <= (x - 2 * (k - 1)); i++) { if (i % 2 == 1) { Console.Write("*"); } else { Console.Write(" "); } } Console.WriteLine(); k--; } Console.ReadLine(); } } } 
+1
source

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); // Returns "Choice1, Choice2" 

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.

+1
source

Printing with a single linq statement:

 var names = Enum.GetValues(typeof(MyEnum)) .Cast<MyEnum>() .Where(a => (values & a) == a) .Select(a => a.ToString()) .Aggregate((current, next) => current + ", " + next); 

An updated version for printing only explicitly defined values:

 var values = MyEnum.All; var allAttrs = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>(); var names = allAttrs // leave only explicitly defined and not zero values .Where(attr => allAttrs.Count(a => a != 0 && (attr & a) == a) == 1) .Where(a => (values & a) == a) .Select(a=>a.ToString()) .Aggregate((current, next) => current + ", " + next); Console.WriteLine(names); // Choice1, Choice2, Choice3 
+1
source

Use flags.ToString("g");
See Listing Format Strings

0
source

All Articles