2010-01-25 20 views
6

Entiendo cómo funcionan los Enum en C#, y obtengo lo que el atributo Flags trae a la mesa.¿Múltiples formas de definir C# Enums con el atributo [Flags]?

Vi esta pregunta, here. Que recomienda el primer sabor, pero no proporciona ninguna razón/justificación para ello.

¿Hay alguna diferencia en la forma en que se definen estos dos, es una mejor que la otra? ¿Cuáles son las ventajas de usar el primer synax como lugar del segundo? Siempre he usado el segundo sabor al definir Flags tipo Enums ... ¿Lo he estado haciendo mal todo este tiempo?

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

Es que no es el mismo que

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

El código IL producido para estos 2 fragmentos de código es el mismo. –

+3

Encuentra el error en este código: BackupOperator = 1073714824. Primero puedes evitar el error diciendo BackupOperator = 1 << 30 –

+0

Gracias por la información, utilizaré el primer acercamiento, ya que parece mejor para todos menos los casos más simples. – Nate

Respuesta

6

La principal ventaja de la primera es que no necesita calcular los valores correctos para cada indicador, ya que el compilador lo hará por usted. Aparte de eso, son lo mismo.

+0

¿Entonces básicamente es un truco de compilación? – Nate

+2

Sí, 1 << n es una constante, por lo que el compilador debería calcularlo, que podría ser menos propenso a errores que 1,2,4,8 ... También podría usar hexadecimal, por ejemplo, hex. 0x1, 0x10, 0x100 ... – Lee

+1

Aunque podría estar más interesado en valores hexadecimales como 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80. –

0

yo sepa que es un debate legibilidad. Algunos dirían que el primero es más legible porque tienes el índice real de la bandera en el lado derecho del '< <'.

+0

¿Esto es realmente un truco de compilación? ¿Desde 1 << 2 = 4? – Nate

+1

No es un truco de compilación. ¿Cuál es la diferencia entre Helpdesk = 1 << 2, Helpdesk = 4 o Helpdesk = 3 + 1. Es solo una expresión que se evalúa. – empi

+0

Supongo que veo eso como aprovechar el compilador y, por lo tanto, un truco de compilación. Tu punto está bien tomado. – Nate

6

Considerar las muestras más complejas:

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

Este muestras muestra que en este caso primera versión es mucho más legible. Los literales decimales no son la mejor forma de representar constantes de banderas. Y para obtener más información sobre las operaciones bit a bit (que también se pueden usar para representar las constantes del indicador), vea http://en.wikipedia.org/wiki/Bitwise_operation

0

. Hay otra manera de hacerlo, que es bastante elegante, así que pensé en compartir algo que recientemente escribí. Tiene el beneficio de requerir muy poca matemática, por lo que creo que es menos propenso a errores. Es muy legible, en mi humilde opinión.

[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: Dado que la enumeración hereda de System.Int32, sólo puedo definir 32 banderas. Si necesita más, deberá usar un número entero más grande (System.Int64), crear más de una enumeración y encadenarlas, o simplemente crear una clase con un grupo de valores booleanos.