2010-01-25 10 views
6

Ich verstehe, wie Enums in C# arbeiten, und ich bekomme, was das Attribut Flags in die Tabelle bringt.Mehrere Möglichkeiten zum Definieren von C# Enums mit Attribut [Flags]?

Ich habe diese Frage gesehen, here. Das empfiehlt den ersten Geschmack, gibt aber keinen Grund/Begründung dafür.

Gibt es einen Unterschied in der Art und Weise, in der diese beiden definiert sind, ist einer besser als der andere? Was sind die Vorteile, wenn Sie das erste Synax anstelle des zweiten verwenden? Ich habe immer den zweiten Geschmack verwendet, wenn ich Flags Typ Enums definiert habe ... habe ich die ganze Zeit falsch gemacht?

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

Ist das nicht das gleiche wie

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

Der für diese 2-Code-Fragmente erzeugte IL-Code ist derselbe. –

+3

Finden Sie den Fehler in diesem Code: BackupOperator = 1073714824. Sie können den Fehler in erster Linie vermeiden, indem Sie BackupOperator = 1 << 30 –

+0

Danke für die Info alle, ich werde den ersten Ansatz verwenden, da es besser scheint für alle außer den einfachsten Fällen. – Nate

Antwort

6

Der Hauptvorteil des ersten ist, dass Sie nicht die richtigen Werte für jedes Flag berechnen müssen, da der Compiler es für Sie tun wird. Ansonsten sind sie gleich.

+0

Also ist es im Grunde ein Compiler-Trick? – Nate

+2

Ja, 1 << n ist eine Konstante, so dass der Compiler es berechnen sollte, die weniger fehleranfällig als 1,2,4,8 sein könnte ... Sie könnten auch hex z. 0x1, 0x10, 0x100 ... – Lee

+1

Auch wenn Sie mehr an Hex-Werten wie 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 interessiert sein könnten. –

0

AFAIK seine Ablesbarkeit Debatte. Einige würden sagen, dass die erste lesbarer ist, weil Sie den tatsächlichen Index der Flagge auf der rechten Seite der "< <" haben.

+0

Ist das effektiv ein Compiler-Trick? Seit 1 << 2 = 4? – Nate

+1

Es ist kein Compiler-Trick. Was ist der Unterschied zwischen Helpdesk = 1 << 2, Helpdesk = 4 oder Helpdesk = 3 + 1. Es ist nur ein Ausdruck, der ausgewertet wird. – empi

+0

Ich denke, ich sehe das als Vorteil des Compilers und somit als Compiler-Trick. Dein Punkt ist gut gemacht. – Nate

6

Betrachten komplexer Proben:

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

Diese Proben zeigt, dass in diesem Fall erste Version ist viel besser lesbar. Dezimal-Literale sind nicht die beste Möglichkeit, Flag-Konstanten darzustellen. Weitere Informationen zu bitweisen Operationen (die auch zur Darstellung von Flag-Konstanten verwendet werden können) finden Sie unter http://en.wikipedia.org/wiki/Bitwise_operation

0

Es gibt eine andere Möglichkeit, dies zu tun, die ziemlich elegant ist, und so dachte ich, ich würde etwas teilen, das ich kürzlich geschrieben habe. Es hat den Vorteil, sehr wenig Mathematik zu benötigen und daher ist es weniger fehleranfällig. Es ist sehr lesbar, 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 
} 

HINWEIS: Da die Aufzählung von System.Int32 erbt, kann ich nur 32 Flaggen definieren. Wenn Sie mehr benötigen, müssen Sie eine größere Ganzzahl (System.Int64) verwenden, mehr als eine Aufzählung erstellen und sie zusammenketten oder einfach eine Klasse mit einer Reihe boolescher Werte erstellen.