Подтвердить что ты не робот

Почему побитовый оператор OR используется в перечислении флагов со значением AND

Это может быть простой и простой вопрос, но у меня все еще есть небольшая путаница, почему используется побитовая OR. Предположим, что у меня есть класс A с четырьмя полями:

class A
{
    private int Field1;
    private static int Field2;
    public int Field3;
    public static int Field4;
}

И используйте Reflection для получения полей:

var fields = typeof (A).GetFields(BindingFlags.Public | BindingFlags.Static);

Если вы новичок с Reflection и не знаете, как использовать BindingFlags, начальное логическое мышление в вашей голове будет:

Эта строка выберет все статические или общедоступные поля, потому что используется побитовое ИЛИ. И ожидаемый результат, который вы думаете:

Field2
Field3
Field4

Но при нажатии F5 результат будет совершенно другим, побитовое OR работает как AND:

Field4

Почему бы не использовать побитовый оператор И, который мог бы следовать логическому мышлению. например:

var fields = typeof (A).GetFields(BindingFlags.Public & BindingFlags.Static);

Я нашел слова в MSDN:

побитовая операция ИЛИ, используемая для объединения флагов, может считаться передовой концепцией в некоторых случаях, которая не должна требоваться для простых задач.

Пожалуйста, можете ли вы объяснить концепцию аванса здесь простым способом для понимания?

4b9b3361

Ответ 1

См. конец краткого резюме.

Длинный ответ:

Побитовое ИЛИ объединяет биты флагов перечисления.

Пример:

  • BindingFlags.Public имеет значение 16 или 10000 (двоичный)
  • BindingFlags.Static имеет значение 8 или 1000 (двоичный)

побитовое ИЛИ объединяет их следующим образом:

10000
01000
--
11000  --> 24

побитовое И объединит их следующим образом:

10000
01000
--
00000   --> 0

Это очень простая концепция флагов:
Каждое значение равно двум, например:

  • 1 = 2^0
  • 2 = 2^1
  • 4 = 2^2
  • 8 = 2^3
  • и др.

Их битовое представление всегда равно 1, а остальные нули:

decimal | binary
1       | 0001
2       | 0010
4       | 0100
8       | 1000

Объединение любого из них с использованием побитового И всегда приведет к 0, так как в той же позиции нет 1. Побитовое И приведет к полной потере информации.

Побитовое ИЛИ, с другой стороны, всегда приведет к однозначному результату. Например, когда у вас есть (двоичный) 1010 (десятичный 10), вы знаете, что изначально это было 8 и 2. Нет другой возможности, которую могли бы создать 10.
По умолчанию, метод, который вы вызвали, может впоследствии извлечь эту информацию с помощью побитового оператора AND:

if(10 & 8 == 8) // value 8 was set

Побитовое ИЛИ в этом случае в основном является транспортным средством для переноса значений в метод, который вы вызываете.
То, что этот метод делает с этими значениями, не имеет ничего общего с использованием побитового ИЛИ.
Он может внутренне требовать, чтобы ВСЕ прошедшие флаги совпадали, как в случае с GetFields. Но для этого также может потребоваться только один из прошедших флажков.

Для вас, как вызывающего, было бы эквивалентно следующее:

var requiredFlags = new List<BindingFlags>();
requiredFlags.Add(BindingFlags.Public);
requiredFlags.Add(BindingFlags.Static);
typeof (A).GetFields(requiredFlags);

Теперь, когда он не компилируется, поскольку GetFields не обеспечивает такую ​​перегрузку, но значение будет таким же, как и для вашего кода.

Подводя итог (TL; DR):

Побитовое И не имеет ничего общего с Boolean AND Побитовое ИЛИ не имеет ничего общего с Boolean OR

Ответ 2

Перечисление флагов используется для представления набора булевых условий.

В вашем примере каждое булевское условие должно быть выполнено для соответствующего поля, которое должно быть возвращено.

Перечисления флагов - это просто интегральные значения, которые подчиняются обычным двоичным правилам для anding и oring, поэтому для установки нескольких бит вы должны ИЛИ вместе значить эти биты.

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

Проблема, с которой вы сталкиваетесь, состоит в том, что вы объединяете два разных понятия: способ построения множества логических условий для перечисления флага - это одна концепция. Способ использования перечисления флага (или того, что он представляет) является другой концепцией.

Первый использует OR для построения множества булевых условий. Последний говорит, что каждый бит представляет собой логическое условие, которое должно быть выполнено.

Ответ 3

Разработчики GetFields() решили интерпретировать комбинацию различных ORed-флагов, что означает комбинацию AND из выбранных критериев.

Что имеет смысл, поскольку вы всегда можете отказаться от критерия, если вы не хотите использовать дополнительный фильтр.