2010-01-25 4 views
6

Capisco come funziona Enums in C# e ottengo ciò che l'attributo Flags porta in tavola.Più modi per definire C# Enum con l'attributo [Flags]?

Ho visto questa domanda, here. Che raccomanda il primo sapore, ma non fornisce alcun motivo/giustificazione per questo.

C'è una differenza nel modo in cui questi due sono definiti, è uno migliore dell'altro? Quali sono i vantaggi nell'usare la prima synax al posto della seconda? Ho sempre usato il secondo sapore quando ho definito i tipi di enumerazione di Flags ... ho sbagliato tutto questo tempo?

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

È che non è la stessa

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

Il codice IL prodotto per questi due frammenti di codice è lo stesso. –

+3

Individuare il bug in questo codice: BackupOperator = 1073714824. È possibile evitare il bug in primo luogo dicendo BackupOperator = 1 << 30 –

+0

Grazie per tutte le informazioni, userò il primo approccio, poiché sembra migliore per tutti tranne i casi più semplici. – Nate

risposta

6

Il vantaggio principale con il primo è che non è necessario calcolare i valori corretti per ogni indicatore poiché il compilatore lo farà per voi. A parte questo, sono uguali.

+0

Quindi è fondamentalmente un trucco per compilatore? – Nate

+2

Sì, 1 << n è una costante, quindi il compilatore dovrebbe calcolarlo, che potrebbe essere meno incline all'errore di 1,2,4,8 ... Potresti anche usare l'es. Es. 0x1, 0x10, 0x100 ... – Lee

+1

Anche se potresti essere più interessato a valori esadecimali come 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80. –

0

per quanto ne so il suo un dibattito leggibilità. Alcuni direbbero che il primo è più leggibile perché si ha l'indice effettivo della bandiera sul lato destro dello '< <'.

+0

Questo è effettivamente un trucco del compilatore? Dal 1 << 2 = 4? – Nate

+1

Non è un trucco per il compilatore. Qual è la differenza tra Helpdesk = 1 << 2, Helpdesk = 4 o Helpdesk = 3 + 1. È solo un'espressione che viene valutata. – empi

+0

Credo di vederlo sfruttando il compilatore e quindi un trucco per il compilatore. Il tuo punto è ben preso. – Nate

6

consideri campioni più complessi:

[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 
} 

Questa campioni dimostra che in questo caso prima versione è molto più leggibile. I letterali decimali non sono il modo migliore per rappresentare le costanti della bandiera. E per ulteriori informazioni sulle operazioni bit a bit (che possono essere utilizzate anche per rappresentare le costanti) vedere http://en.wikipedia.org/wiki/Bitwise_operation

0

C'è un altro modo per farlo che è piuttosto elegante e quindi ho pensato di condividere qualcosa che ho scritto di recente. Ha il vantaggio di richiedere pochissima matematica e quindi penso che sia meno incline agli errori. È molto leggibile, IMHO.

[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 
} 

NOTA: Dal momento che l'enumerazione eredita da System.Int32, posso definire solo 32 bandiere. Se hai bisogno di più dovrai usare un numero intero più grande (System.Int64), creare più di un'enumerazione e metterli insieme, o semplicemente creare una classe con un gruppo di valori booleani.