Как работает объединение битов перечисления атрибута c # flags? - PullRequest
0 голосов
/ 06 февраля 2019

Атрибут Flags для перечислений позволяет переменным этого типа перечисления принимать более одного значения через битовую логику.Вот почему для каждого члена перечисления рекомендуется иметь числовое значение, равное 2 или 0.

Однако C # не не препятствует определить элемент со значениемскажем, 3.

В связи с этим возникает вопрос - как C # объединяет флаги, в которых члены имеют числовое значение, которое не равно 0 или 2, возведенное в степень?

Например, обычныйflags enum будет производить что-то вроде (взято из ссылки MSDN выше):

// Define an Enum with FlagsAttribute.
[Flags] 
enum MultiHue : short
{
   None = 0,
   Black = 1,
   Red = 2,
   Green = 4,
   Blue = 8
};

static void Main( )
{
  // Display all combinations of values, and invalid values.
  Console.WriteLine("\nAll possible combinations of values with FlagsAttribute:");

  for( int val = 0; val <= 16; val++ )
     Console.WriteLine( "{0,3} - {1:G}", val, (MultiHue)val);
}

//       All possible combinations of values with FlagsAttribute:
//         0 - None
//         1 - Black
//         2 - Red
//         3 - Black, Red
//         4 - Green
//         5 - Black, Green
//         6 - Red, Green
//         7 - Black, Red, Green
//         8 - Blue
//         9 - Black, Blue
//        10 - Red, Blue
//        11 - Black, Red, Blue
//        12 - Green, Blue
//        13 - Black, Green, Blue
//        14 - Red, Green, Blue
//        15 - Black, Red, Green, Blue
//        16 - 16

Однако, если бы я добавил другого члена в перечисление «MultiHue» с числовым значением «3», это произойдет:

// Define an Enum with FlagsAttribute.
[Flags] 
enum MultiHue : short
{
   None = 0,
   Black = 1,
   Red = 2,
   Lime = 3,
   Green = 4,
   Blue = 8
};

static void Main( )
{
  // Display all combinations of values, and invalid values.
  Console.WriteLine("\nAll possible combinations of values with FlagsAttribute:");

  for( int val = 0; val <= 16; val++ )
     Console.WriteLine( "{0,3} - {1:G}", val, (MultiHue)val);
}

  0 - None
  1 - Black
  2 - Red
  3 - Lime
  4 - Green
  5 - Black, Green
  6 - Red, Green
  7 - Lime, Green
  8 - Blue
  9 - Black, Blue
 10 - Red, Blue
 11 - Lime, Blue
 12 - Green, Blue
 13 - Black, Green, Blue
 14 - Red, Green, Blue
 15 - Lime, Green, Blue
 16 - 16

Обратите внимание на то, как разные комбинации могут быть представлены с разными членами, например:

4 - это "зеленый", однако это может быть и "лайм, черный".7 - «Лайм, зеленый», вместо предыдущего «Черный, красный, зеленый»и т.д.

Я знаю, что это плохая практика, но я хочу знать, как компилятор решает, какую комбинацию элементов использовать для определенной битовой комбинации?

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Речь не идет о запрете или разрешении комбинаций или побитовых операторов (допускается либо с атрибутом Flags или без него), поскольку это указывает на то, что побитовое имеет смысл, и влияет на работу ToString().

Рассмотрим:

public enum Color
{
    Black = 0,
    Blue = 1,
    Green = 2,
    Red = 4
}

Это позволило бы нам осмысленно говорить о 8 цветах в зависимости от того, были ли заданы заданные синие, зеленые или красные флаги.

Мы могли бы определить эти комбинациивнутри перечисления:

public enum Color
{
    Black = 0,
    Blue = 1,
    Green = 2,
    Cyan = 3,
    Red = 4,
    Magenta = 5,
    Yellow = 6,
    White = 7
}

Обратите внимание, что здесь функциональность одинакова: Color.Green | Color.Red имеет одинаковое значение 6 в любом случае, что, конечно, будет означать желтый.Разница в том, дадим ли мы удобную метку Yellow или нет.

Основное различие между моим перечислением и вашим состоит в том, что мои комбинации имеют какой-то общий смысл, потому что зеленый и красный свет смешиваются ссделать желтый и так далее.Как правило, нам будет полезно назвать только 1-битные значения (1, 2, 4, 8 ...), но иногда именование конкретных общих комбинаций полезно для кодировщика, использующего перечисление.Реальный пример этого - DateTimeStyles.В этом перечислении AllowLeadingWhite имеет значение 1, AllowTrailingWhite имеет значение 2, AllowInnerWhite имеет значение 4, а AllowWhiteSpaces имеет значение 7 как удобный способ указать все эти трифлаги установлены.

0 голосов
/ 06 февраля 2019

Если вы напишите это в двоичном виде, вы увидите.

1 - black - 00000001
2 - red   - 00000010
3 - lime  - 00000011

Так что 3 не лайм, он должен быть черным.3 черный и красный.Вы можете установить не только степени 2 для более удобных комбинаций.Вместо сравнения с черным и красным вы можете сравнить с черным.

...