2016-06-13 143 views
1

我已經定義了這樣的一個枚舉:有沒有辦法判斷一個枚舉是否只有一個,多個或不設置標誌?

[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; 
+2

這看起來不對。你真的可以有一個既是北方又是南方的方向? –

+0

@JonathanAllen是的,不要想一個我可以花一點時間的方向。想想哪些方向可用。可能是「方向」在這裏是錯誤的措詞;) – Norman

+1

@ Dennis_E不是真的,因爲你可以擁有像'(Orientation)1023'這樣的東西,當只有8個標誌時它有10個位。 – juharr

回答

3

您可以使用此代碼:

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

甚至可能是一行Linq'int i = Enum.GetValues(typeof(Orientation))。Cast ().Where(o => item.HasFlag(o))。Count();' – juharr

+0

想到有一個比行走一個循環或使用LINQ更短的方式,但顯然沒有... – Norman

+0

我選擇這一個作爲解決方案,但我實際上使用juharr的方法(這在技術上是識別性的)。這似乎是最合理的 - 即使我喜歡Slai用ToString想的方式。 – Norman

1

關閉頂部我的頭:

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 
} 
2
var test = Orientation.North; 
var flagCount = GetFlagCount(test); 

public int GetFlagCount(Enum testValue) 
{ 
    return Enum.GetValues(testValue.GetType()).Cast<Enum>().Count(testValue.HasFlag); 
} 
+0

你正在使用哪個目標框架?在.Net 4.5.2中,一個數組(GetValues)不包含count這個參數的定義... – Norman

+0

對不起,我從我的電話回答,所以沒有可能試用它。我已經更新了我的答案。 –

0

您可以將值轉換爲後,用簡單的位伎倆確定這3210:

int v =(int)enumValue;

  1. 如果v == 0,則未設置任何標誌
  2. 否則,如果((v-1)&v) == 0,則只有一個標誌設置
  3. ,否則,多個標誌設置。

唯一棘手的是#2。這是一個解釋:考慮一個二進制數字,其中一位設置爲1。然後減去1將作出以下修改:

0000010000000 
-    1 
    ------------- 
    0000001111111 

所有零以下獨行1成爲1 S,1變爲零,而其餘位保持不變。 AND -ing vv-1產生零,因爲在兩個數字之間的相同位置沒有一對1 s。

當有兩個或更多個1 s時,位於唯一1左側的位將保持不變。因此,在按位AND的結果中至少有一個位置將具有1

2

如果您正在尋找 「最短」 的方式:

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 我個人不會在生產中使用的代碼串的方法,需要只是有點計數時尤其如此。

無論如何,我只是爲了好玩而想到另一個黑客。當設置一位時,Base 2日誌將返回一個完整的數字,當爲0時爲無窮大,當設置多個位時爲其他數據。對於實施例

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的解決方案似乎是最好的。

+1

這是一種很酷的ToString()濫用。你也可以分開逗號。 'foo.ToString()=「Foo,Bizz」' – DVK

+0

我喜歡你的思維方式,而且tostring-split方法非常整齊。但是... ToString在任何平臺,任何地區,任何c#版本上的行爲是否一致? – Norman

0

這不是計數位數的重複。如果我初始化這樣的枚舉和計數位,我得到10的數量,但一組標誌的數目是8。

請直接from 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); 
+0

var bar =(MyEnum)27在代碼中我不會做任何事情。但由於枚舉的值以int形式存儲在數據庫中,因此您可以在不知道枚舉的情況下將其更改爲任何值。 – Norman

相關問題