Is there a way to tell if an enum has exactly one, multiple or no flags set?
我有一个这样定义的枚举:
1 2 3 4 5 6 7 8 9 10 11 12 | [Flags] public enum Orientation { North = 1, North_East = 2, East = 4, South_East = 8, South = 16, South_West = 32, West = 64, North_West = 128 } |
是否有一种通用的方法来判断是否只设置了一个标志、多个标志或无标志?我不关心枚举的值是什么,我只想知道设置了多少个标志。
这不是用于计算位数的副本。如果我像这样初始化枚举并计算得到的位数10。但设置标志的数量将是8个。
1 | GeographicOrientation go = (GeographicOrientation) 1023; |
您可以使用此代码:
1 2 3 4 5 6 7 | var item = Orientation.North | Orientation.South; int i = 0; foreach (Orientation e in Enum.GetValues(typeof(Orientation))) if(item.HasFlag(e)) i++; Console.WriteLine(i); |
1 2 3 4 5 6 7 | var test = Orientation.North; var flagCount = GetFlagCount(test); public int GetFlagCount(Enum testValue) { return Enum.GetValues(testValue.GetType()).Cast<Enum>().Count(testValue.HasFlag); } |
如果您正在寻找"最短"的方法:
1 2 | Orientation o = Orientation.East | Orientation.West; // o.ToString() ="East, West" var c = o.ToString().Split().Count(); |
或者更短:
1 | var c = (o +"").Split().Count(); |
更新
要支持高于255的值,您可以使用任何这些丑陋的黑客:
1 2 3 | Orientation o = (Orientation) 1023; var c = ((Orientation)(byte)o +"").Split().Count(); c = ((Orientation)((int)o & 255) +"").Split().Count(); |
或者将枚举定义为字节:
1 2 3 4 5 6 7 8 9 10 11 12 | [Flags] public enum Orientation : byte { North = 1, North_East = 2, East = 4, South_East = 8, South = 16, South_West = 32, West = 64, North_West = 128 } |
更新2我个人不会在生产代码中使用string方法,特别是在只需要计算一点的时候。
不管怎样,我只是想到了另一个黑客只是为了好玩。以2为基数的日志将在设置一个位时返回一个整数,0时返回无穷大,设置多个位时返回任何其他值。例如
1 2 3 | Math.Log(0, 2 ) // -Infinity Math.Log(0, 64) // 6.0 Math.Log(0, 65) // 6.0223678130284544 |
因此,可以使用
但是,达斯布林肯利特的解决方案似乎是最好的。
在我的头顶上:
1 2 3 4 5 6 7 8 9 | var map = 1; var count = 0; while (map <= North_West) { if( ((int)Value & map) > 0) count += 1; map = map << 1; //left shift, a.k.a. multiply by 2 } |
This is not a duplicate for counting the number of bits. If I initialize the enum like this and count the number of bits I get 10. But the number of set flags would be 8.
请直接考虑来自msdn的声明:
Flags enumerations are used for masking bit fields and doing bitwise comparisons.
如果您以某种方式设计或使用枚举,而不允许使用按位操作计算标志数,则说明您设计或使用枚举不正确。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | [Flags] public enum MyEnum { Foo = 1, Bar = 2, Bizz = 4, Buzz = 8, Boo = 16 } var foo = MyEnum.Foo | MyEnum.Foo | MyEnum.Bizz; // foo == MyEnum.Foo | MyEnum.Bizz because setting the same flag twice does nothing var bar = (MyEnum)27 // Some invalid combination // bar == 27. Why would you do this instead of MyEnum.Boo | MyEnum.Buzz | MyEnum.Bar | MyEnum.Foo |
如果正确设计枚举,则可以对标志进行计数,如果设置了多个标志,则可以选择短路,因为继续计数将是无意义的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var foo = MyEnum.Foo | MyEnum.Bizz; int fooValue = (int)foo; int numberOfFlags = 0; while (fooValue > 0 && numberOfFlags < 2) // Stop counting if more than one flag since we don't need exact count { if ((fooValue & 1) == 1) { numberOfFlags++; } fooValue >>= 1; } Console.WriteLine(numberOfFlags); |
在将值转换为
int v=(int)枚举值;
唯一棘手的是2。这里有一个解释:考虑一个二进制数,它恰好有一个位设置为
1 2 3 4 | 0000010000000 - 1 ------------- 0000001111111 |
单独的
当存在两个或多个