Использование побитовых операторов на флагах - PullRequest
26 голосов
/ 10 февраля 2009

У меня есть четыре флага

Current = 0x1  
Past = 0x2  
Future = 0x4  
All = 0x7

Скажите, что я получил два флага: Прошлое и Будущее (setFlags(PAST | FUTURE)) Как я могу определить, есть ли в нем Past? Кроме того, как я могу сказать, что Current не в нем? Таким образом, мне не нужно проверять каждую возможную комбинацию.

Ответы [ 8 ]

43 голосов
/ 10 февраля 2009

Если вы хотите, чтобы все биты в тестовой маске совпадали:

if((value & mask) == mask) {...}

Если вы хотите, чтобы любой бит в тестовой маске совпадал:

if((value & mask) != 0) {...}

Разница наиболее заметна, когда вы тестируете значение для нескольких вещей.

Для проверки на исключение:

if ((value & mask) == 0) { }
29 голосов
/ 10 февраля 2009

Прежде всего - используйте перечисления с FlagAttribute. Вот для чего это.

[Flags]
public enum Time
{
    None = 0
    Current = 1,
    Past = 2,
    Future = 4
    All = 7
}

Затем выполняется тестирование следующим образом:

if ( (x & Time.Past) != 0 )

Или это:

if ( (x & Time.Past) == Time.Past )

Последний будет работать лучше, если «Прошлое» было комбинацией флагов, и вы хотели проверить их все.

Настройка такая:

x |= Time.Past;

Отключение выглядит так:

x &= ~Time.Past;
12 голосов
/ 10 февраля 2009

Вы также можете добавить метод расширения , например,

  enum states {
     Current = 0x1,
     Past = 0x2,
     Future = 0x4,
     All = 0x7
  };

  static bool Is(this states current, states value) {
     return (current & value) == value;
  }

тогда вы можете сделать:

 if(state.Is(states.Past)) {
    // Past
 }
4 голосов
/ 10 февраля 2009
if ((flags & PAST) == PAST)
{
  // PAST is there
}

if ((flags & CURRENT) != CURRENT)
{
  // CURRENT is not there
}
3 голосов
/ 20 апреля 2018

Если вы используете .NET 4 или более позднюю версию, я предпочитаю делать это, чище imao:

[Flags]
public enum Time
{
    None = 0
    Current = 1,
    Past = 2,
    Future = 4
}

myProp = Time.Past | Time.Future;

if (myProp.HasFlag(Time.Past))
{
    // Past is set...
}
1 голос
/ 22 сентября 2014

Приложение к Марку Гравеллу и ответ Вилкса:

Ваше помеченное перечисление не должно указывать сумму для «Все», оно должно просто включать ваши существующие значения. Это касается любых вычисленных значений.

[Flags]
public enum Time
{
    None = 0,
    Current = 1,
    Past = 2,
    Future = 4,
    All = Current | Past | Future
}

Обратите внимание, что Vilx - убрал использование шестнадцатеричного значения. Это важно, потому что как только вы пройдете 0x8, ваши значения должны будут соответствовать Hex. Вы должны просто остаться в десятичном виде.

EDIT: Я также хочу добавить, что вы можете использовать битовое смещение, а не шестнадцатеричное / десятичное.

Это выглядит так:

[Flags]
public enum Time
{
    None = 0,
    Current = 1,
    Past = 1 << 1, // 2, 10 binary
    Future = 1 << 2, // 4, 100 binary
    All = Current | Past | Future
}
0 голосов
/ 10 февраля 2009
(value & Current) == Current
0 голосов
/ 10 февраля 2009

вы можете использовать AND и проверить, совпадает ли результат с вами и с?

...