[英]Is there a way to tell if an enum has exactly one, multiple or no flags set?
我有一個這樣定義的枚舉:
[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。
GeographicOrientation go = (GeographicOrientation) 1023;
您可以使用以下代碼:
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);
var test = Orientation.North;
var flagCount = GetFlagCount(test);
public int GetFlagCount(Enum testValue)
{
return Enum.GetValues(testValue.GetType()).Cast<Enum>().Count(testValue.HasFlag);
}
如果您正在尋找“最短”的方式:
Orientation o = Orientation.East | Orientation.West; // o.ToString() = "East, West"
var c = o.ToString().Split().Count();
甚至更短:
var c = (o + "").Split().Count();
更新資料
要支持大於255的值,您可以使用以下任何丑陋的技巧:
Orientation o = (Orientation) 1023;
var c = ((Orientation)(byte)o + "").Split().Count();
c = ((Orientation)((int)o & 255) + "").Split().Count();
或者只是將枚舉定義為字節:
[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我個人不會在生產代碼中使用字符串方法,尤其是在只需要一點計數的時候。
無論如何,我只是想到了另一個樂趣。 設置一位時,以2為底的日志將返回整數;設置為0時,-Infinity將返回整數;如果設置一位以上,則以其他形式返回。 例如
Math.Log(0, 2 ) // -Infinity
Math.Log(0, 64) // 6.0
Math.Log(0, 65) // 6.0223678130284544
因此,可以使用(byte)go != 0
來檢查是否設置了任何標志,然后使用Math.Log((byte)go, 2) % 1 == 0
來檢查是否僅設置了一個標志。
但是,dasblinkenlight的解決方案似乎是最好的。
從我的頭頂上:
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
}
將值轉換為int
之后,可以用簡單的技巧來確定:
int v =(int)枚舉值;
v == 0
,則不設置標志 ((v-1)&v) == 0
,則僅設置一個標志 唯一棘手的是#2。 這是一個解釋:考慮一個二進制數,將一位精確地設置為1
。 然后減去1
將進行以下更改:
0000010000000
- 1
-------------
0000001111111
孤行1
之后的所有零變為1
s, 1
變為零,其余位保持不變。 AND
-ing v
和v-1
產生零,因為兩個數字之間在相同位置沒有一對1
。
當存在兩個或多個1
s時,孤島1
左側的位將保持不變。 因此,按位AND
的結果至少有一個位置為1
。
這不是重復的位數計數。 如果我這樣初始化枚舉並計算位數,我將得到10。但是設置標志的數量將是8。
請直接從MSDN考慮以下聲明:
標志枚舉用於屏蔽位字段並進行按位比較 。
如果您以某種不允許按位運算計數標志數的方式設計或使用枚舉,則說明您在設計或使用枚舉時使用不正確。
[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
如果您正確地設計了枚舉,則可以對標志進行計數,如果設置了多個標志,則可以選擇短路,因為繼續計數將毫無意義。
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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.