Почему разрешения enum часто имеют значения 0, 1, 2, 4? - PullRequest
156 голосов
/ 21 марта 2012

Почему люди всегда используют значения перечисления, такие как 0, 1, 2, 4, 8, а не 0, 1, 2, 3, 4?

Это как-то связано с битовыми операциями и т. Д.?

Я был бы очень признателен за небольшой фрагмент кода о том, как это правильно используется:)

[Flags]
public enum Permissions
{
    None   = 0,
    Read   = 1,
    Write  = 2,
    Delete = 4
}

Ответы [ 7 ]

264 голосов
/ 21 марта 2012

Потому что это силы двух, и я могу сделать это:

var permissions = Permissions.Read | Permissions.Write;

И возможно позже ...

if( (permissions & Permissions.Write) == Permissions.Write )
{
    // we have write access
}

Это битовое поле, где каждый установленный бит соответствует определенному разрешению (или тому, что логически соответствует перечисляемому значению). Если бы они были определены как 1, 2, 3, ..., вы не смогли бы использовать побитовые операторы таким образом и получить значимые результаты. Углубиться глубже ...

Permissions.Read   == 1 == 00000001
Permissions.Write  == 2 == 00000010
Permissions.Delete == 4 == 00000100

Заметили здесь схему? Теперь, если мы возьмем мой оригинальный пример, то есть

var permissions = Permissions.Read | Permissions.Write;

Тогда ...

permissions == 00000011

См? Биты Read и Write установлены, и я могу проверить это независимо (также обратите внимание, что бит Delete равен , а не установлен, и, следовательно, это значение не передает разрешение на удаление).

Позволяет хранить несколько флагов в одном поле битов.

144 голосов
/ 21 марта 2012

Если из других ответов все еще неясно, подумайте об этом так:

[Flags] 
public enum Permissions 
{   
   None = 0,   
   Read = 1,     
   Write = 2,   
   Delete = 4 
} 

- это просто более короткий способ написать:

public enum Permissions 
{   
    DeleteNoWriteNoReadNo = 0,   // None
    DeleteNoWriteNoReadYes = 1,  // Read
    DeleteNoWriteYesReadNo = 2,  // Write
    DeleteNoWriteYesReadYes = 3, // Read + Write
    DeleteYesWriteNoReadNo = 4,   // Delete
    DeleteYesWriteNoReadYes = 5,  // Read + Delete
    DeleteYesWriteYesReadNo = 6,  // Write + Delete
    DeleteYesWriteYesReadYes = 7, // Read + Write + Delete
} 

Существует восемь возможностейно вы можете представлять их как комбинации только четырех членов.Если бы было шестнадцать вариантов, вы могли бы представлять их как комбинации только пяти участников.Если бы было четыре миллиарда возможностей, вы могли бы представлять их как комбинации только из 33 участников!Очевидно, что гораздо лучше иметь только 33 члена, каждый (кроме нуля) со степенью двойки, чем пытаться назвать четыре миллиарда предметов в перечислении.

36 голосов
/ 21 марта 2012

Поскольку эти значения представляют уникальные битовые позиции в двоичном формате:

1 == binary 00000001
2 == binary 00000010
4 == binary 00000100

и т. Д., Поэтому

1 | 2 == binary 00000011

EDIT:

3 == binary 00000011

3 в двоичном виде представлен значением 1 как в одном, так и в двойном разрядах. На самом деле это то же самое, что и значение 1 | 2. Поэтому, когда вы пытаетесь использовать двоичные места в качестве флагов для представления некоторого состояния, значение 3 обычно не имеет смысла (если только нет логического значения, которое фактически является комбинацией двух)

Для дальнейшего пояснения вы можете расширить пример перечисления следующим образом:

[Flags]
public Enum Permissions
{
  None = 0,   // Binary 0000000
  Read = 1,   // Binary 0000001
  Write = 2,  // Binary 0000010
  Delete = 4, // Binary 0000100
  All = 7,    // Binary 0000111
}

Следовательно, у меня есть Permissions.All, у меня также неявно есть Permissions.Read, Permissions.Write и Permissions.Delete

9 голосов
/ 01 апреля 2012
[Flags]
public Enum Permissions
{
    None   =    0; //0000000
    Read   =    1; //0000001
    Write  = 1<<1; //0000010
    Delete = 1<<2; //0000100
    Blah1  = 1<<3; //0001000
    Blah2  = 1<<4; //0010000
}

Я думаю, что писать так легче понять и читать, и вам не нужно его вычислять.

5 голосов
/ 21 марта 2012

Они используются для представления битовых флагов, которые допускают комбинации значений перечисления. Я думаю, что будет понятнее, если вы напишите значения в шестнадцатеричной записи

[Flags]
public Enum Permissions
{
  None =  0x00,
  Read =  0x01,
  Write = 0x02,
  Delete= 0x04,
  Blah1 = 0x08,
  Blah2 = 0x10
}
1 голос
/ 25 апреля 2013

Множество хороших ответов на этот вопрос ... Я просто скажу ... если вам не нравится, или не может легко понять , что пытается выразить синтаксис <<. Я лично предпочитаюальтернатива (и, смею сказать, простой стиль объявления enum)…

typedef NS_OPTIONS(NSUInteger, Align) {
    AlignLeft         = 00000001,
    AlignRight        = 00000010,
    AlignTop          = 00000100,
    AlignBottom       = 00001000,
    AlignTopLeft      = 00000101,
    AlignTopRight     = 00000110,
    AlignBottomLeft   = 00001001,
    AlignBottomRight  = 00001010
};

NSLog(@"%ld == %ld", AlignLeft | AlignBottom, AlignBottomLeft);

LOG 513 == 513

Намного проще (дляЯ, по крайней мере), чтобы понять.Выстроите их в ряд ... опишите результат, который вы хотите, получите результат, который вы ХОТИТЕ. Никаких "вычислений" не требуется.

1 голос
/ 27 марта 2012

Это действительно больше комментарий, но так как он не поддерживает форматирование, я просто хотел включить метод, который я использовал для настройки перечисления флагов:

[Flags]
public enum FlagTest
{
    None = 0,
    Read = 1,
    Write = Read * 2,
    Delete = Write * 2,
    ReadWrite = Read|Write
}

Я нахожу такой подходособенно полезно во время разработки в случае, если вы хотите поддерживать свои флаги в алфавитном порядке.Если вы решите, что вам нужно добавить новое значение флага, вы можете просто вставить его в алфавитном порядке, и единственное значение, которое вам нужно изменить, - это значение, которое ему предшествует.

Обратите внимание, что после публикации решенияЛюбая производственная система (особенно, если перечисление открыто без сильной связи, например, через веб-сервис), тогда настоятельно рекомендуется не изменять любое существующее значение внутри перечисления.

...