[.NET C#] 位元運算用的列舉型別 FlagsAttribute

  • 1057
  • 0
  • C#
  • 2015-06-16

.NET Framework除了一般開發者很常使用的列舉型別外(Enumeration), 原來也有支援複合列舉的使用,在MSDN中文翻譯為旗標(Flag), 其實早在.NET 1.1就開始支援了(汗,過去專案中還真的沒有使用過), 這種標示為旗標的列舉,最大的差別就是該型別被認定會直接拿來進行位元運算。

.NET Framework除了一般開發者很常使用的列舉型別外(Enumeration), 原來也有支援複合列舉的使用,在MSDN中文翻譯為旗標(Flag), 其實早在.NET 1.1就開始支援了(汗,過去專案中還真的沒有使用過), 這種標示為旗標的列舉,最大的差別就是該型別被認定會直接拿來進行位元運算。

[SerializableAttribute]
[AttributeUsageAttribute(AttributeTargets.Enum, Inherited = false)]
[ComVisibleAttribute(true)]
public class FlagsAttribute : Attribute

這個Flag Attribute直接繼承了Attribute類別, 並且只能標示於Enum的型別上,而且無法繼承,一旦Enum被標示了此Attribute,則被視為該型別物件會直接做位元運算,所以在MSDN的GuideLine上, 也表明此種列舉方式正常以2的次方來設定其值:

“以乘冪數 2 來定義列舉常數,也就是 1、2、4、8 等。 這表示在結合的列舉常數中的個別旗標不會重疊。

一般最常作的應用應該就算權限了, 我們可以針對每一個二次方數字設定其對應擁有權限如下:

[Flags]
    public enum enumPermission
    {
        Guest = 1,
        Member = 2,
        Leader = 4,
        Manager = 8,
    }

然後列出這個列舉的所有組合

//All Combination of flag enumation
            for (int val = 0; val <= 16; val++)
                Console.WriteLine("{0,3} - {1:G}", val, (enumPermission)val);

並試著以迴圈執行此Flag Enum所有的可能情境, 如下圖所列,如此在權限欄位設定中,預設會有0~15種組合。

而在權限的判斷上,當然也就要用位元運算的OR / AND。如果今天我們想判斷所有具有Member權限的組合, 藉由(val & enumPermission.Member) == enumPermission.Member 即可判斷出

//All Combination of Member permission flag enumation
            for (int val = 0; val <= 16; val++)
            {
                if ((val & (int)enumPermission.Member) == (int)enumPermission.Member)
                    Console.WriteLine("{0,3} - {1:G}", val, (enumPermission)val);
            }

如此我們便可以捉出所有具有Member權限的組合。

 

由在權限設定上, 則是用OR的方式來達到

enumPermission p = (0 | enumPermission.Member);
            p = (p | enumPermission.Manager);
            Console.WriteLine(p);

 

如此可以設定一個p變數具有Member及Manager的權限,而利用列舉的好處讓可讀性很高。

從.NET 1.1就有的東西居然過了十多年才發現,藉由撰寫這篇把玩了一下,也讓自已不會忘記。

 

參考

https://msdn.microsoft.com/zh-tw/library/System.FlagsAttribute(v=vs.110).aspx