Несколько способов определить C # Enums с атрибутом [Flags]? - PullRequest
6 голосов
/ 25 января 2010

Я понимаю, как Enums работает в C #, и я получаю то, что атрибут Flags приносит в таблицу.

Я видел этот вопрос, здесь . Который рекомендует первый аромат, но не предоставляет никакой причины / оправдания для него.

Есть ли разница в том, как эти два определены, один лучше, чем другой? Каковы преимущества использования первого синакса вместо второго? Я всегда использовал второй вариант при определении типа Enums для Flags ... я все это время делал неправильно?

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

Ответы [ 4 ]

6 голосов
/ 25 января 2010

Основным преимуществом первого является то, что вам не нужно вычислять правильные значения для каждого флага, так как компилятор сделает это за вас. Кроме того, они одинаковы.

6 голосов
/ 25 января 2010

Рассмотрим более сложные образцы:

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

Этот пример показывает, что в этом случае первая версия НАМНОГО БОЛЬШЕ читаема. Десятичные литералы - не лучший способ представления констант флага. А для получения дополнительной информации о побитовых операциях (которые также могут использоваться для представления констант флага) см. http://en.wikipedia.org/wiki/Bitwise_operation

0 голосов
/ 11 июля 2013

Есть еще один способ сделать это, довольно элегантный, и поэтому я решил поделиться чем-то, что я недавно написал. Преимущество в том, что он требует очень мало математики, и поэтому я думаю, что он менее подвержен ошибкам. Это очень читабельно, ИМХО.

[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), создать более одного перечисления и объединить их в цепочку или просто создать класс с кучей логических значений.

0 голосов
/ 25 января 2010

AFAIK это дискуссия о читабельности. Кто-то скажет, что первое более читабельно, потому что у вас есть фактический индекс флага справа от '<<'. </p>

...