2010-01-25 20 views
6

我明白了Enums如何在C#中工作,並且我得到了Flags屬性爲表格帶來的效果。用[Flags]屬性定義C#枚舉的多種方法?

我看到了這個問題,here。其中推薦了第一種口味,但沒有提供任何理由/理由。

有沒有在這兩個的定義方式的差異,是一個比其他更好嗎?使用第一個synax而不是第二個優點是什麼?定義標誌類型枚舉時,我總是使用第二種風格......我這一直做錯了嗎?

[Serializable] 
[Flags] 
public enum SiteRoles 
{ 
    User = 1 << 0, 
    Admin = 1 << 1, 
    Helpdesk = 1 << 2 
} 

那是不一樣的

[Serializable] 
[Flags] 
public enum SiteRoles 
{ 
    User = 1, 
    Admin = 2, 
    Helpdesk = 4 
} 
+0

這些2個代碼片段(fragments)產生的IL代碼是相同的。 – 2010-01-25 17:36:14

+3

現貨在此代碼的bug:BackupOperator = 1073714824.您可以通過說出BackupOperator = 1 << 30 – 2010-01-25 18:53:06

+0

感謝您的信息全部,我將使用第一形式給出避免在首位的缺陷,因爲它似乎更好除了最簡單的情況外。 – Nate 2010-01-26 14:09:28

回答

6

與第一個主要優點是,你不需要計算每個標誌的正確值,因爲編譯器會爲你做到這一點。除此之外它們是一樣的。

+0

那麼它基本上是一個編譯器技巧? – Nate 2010-01-25 17:37:35

+2

是的,1 << n是一個常量,所以編譯器應該計算出它的誤差小於1,2,4,8 ......你也可以使用十六進制等。 0x1,0x10,0x100 ... – Lee 2010-01-25 17:41:33

+1

儘管您可能對0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80等十六進制值更感興趣。 – 2010-01-27 19:20:18

0

據我所知它的可讀性辯論。有些人會說第一個更具可讀性,因爲您在'< <'的右側有實際的國旗索引。

+0

這是有效的編譯器技巧嗎?由於1 << 2 = 4? – Nate 2010-01-25 17:37:01

+1

這不是編譯器技巧。 Helpdesk = 1 << 2,Helpdesk = 4或Helpdesk = 3 + 1有什麼區別?它只是一個被評估的表達式。 – empi 2010-01-25 17:39:54

+0

我想我會看到,利用編譯器,因此編譯器技巧。你的觀點很好。 – Nate 2010-01-25 17:54:07

6

考慮更復雜的樣品:

[Flags] 
public enum SiteRoles 
{ 
    User = 1 << 12, 
    Admin = 1 << 13, 
    Helpdesk = 1 << 15, 
    AdvancedUser = User | Helpdesk, //or (1<<12)|(1<<13) 
} 

[Flags] 
public enum SiteRoles 
{ 
    User = 4096, //not so obvious! 
    Admin = 8192, 
    Helpdesk = 16384, 
    AdvancedUser = 12288, //! 
} 

[Flags] 
public enum SiteRoles 
{ 
    User = 0x1000, //we can use hexademical digits 
    Admin = 0x2000, 
    Helpdesk = 0x4000, 
    AdvancedUser = 0x3000, //it much simpler calculate binary operator OR with hexademicals 
} 

該樣品顯示,在這種情況下,第一個版本是更可讀。十進制文字不是表示標誌常量的最佳方式。有關按位運算(也可用於表示標誌常量)的更多信息,請參閱​​

0

還有另一種方法可以做到這一點,它相當優雅,所以我想我會分享一些我最近寫的東西。它具有需要很少數學的好處,所以我認爲它不太容易出錯。這是非常可讀的,恕我直言。

[Flags][Serializable] 
public enum ScopeType : int 
{ 
    Unknown = 0, 
    Global = 1, 
    Namespace = Global << 1, 
    Class = Namespace << 1, 
    Struct = Class << 1, 
    Interface = Struct << 1, 
    Enum = Interface << 1, 
    Function = Enum << 1, 
    Property = Function << 1, 
    PropertyGetter = Property << 1, 
    PropertySetter = PropertyGetter << 1, 
    Using = PropertySetter << 1, 
    If = Using << 1, 
    ElseIf = If << 1, 
    Else = ElseIf << 1, 
    Switch = Else << 1, 
    Case = Switch << 1, 
    For = Case << 1, 
    While = For << 1, 
    DoWhile = While << 1, 
    Lambda = DoWhile << 1, 
    Try = Lambda << 1, 
    Catch = Try << 1, 
    Finally = Catch << 1, 
    Initializer = Finally << 1, 
    Checked = Initializer << 1, 
    Unchecked = Checked << 1, 
    Unsafe = Unchecked << 1, 
    Lock = Unsafe << 1, 
    Fixed = Lock << 1, 

    // I can also group flags together using bitwise-OR. 
    PropertyAccessor = PropertyGetter | PropertySetter, 
    TypeDefinition = Class | Struct | Interface | Enum, 
    TryCatchFinally = Try | Catch | Finally, 
    Conditional = If | ElseIf | Else, 
    Branch = Conditional | Case | TryCatchFinally, 
    Loop = For | While | DoWhile 
} 

注意:由於枚舉繼承自System.Int32,我只能定義32個標誌。如果你需要更多,你將不得不使用一個更大的整數(System.Int64),創建多個枚舉並將它們鏈接在一起,或者只是用一堆布爾值創建一個類。