c#标志属性枚举位组合如何工作?

时间:2019-02-06 11:23:38

标签: c# enums bit-manipulation bitflags

枚举的Flags attribute允许该枚举类型的变量通过位逻辑取多个值。这就是为什么建议每个枚举成员都使用2或0的幂的数字值的原因。

但是C#不能阻止定义一个值为3的成员。

哪个提出了一个问题-C#如何组合带有数字值不为0或2的成员的幂的标志?

例如,普通的标志枚举将产生类似的东西(取自上面的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

但是,如果我要向数字“ 3”中的“ MultiHue”枚举中添加另一个成员,则会生成:

// 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 :(得分:2)

这不是禁止或允许组合或按位运算符(允许或不带有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,指示这三个标志都已设置的简便方法。

答案 1 :(得分:0)

如果以二进制形式编写,则可以看到。

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

所以3不是石灰,应该是黑色红色。 3是黑色和红色。您不仅可以将2的幂设置为更易于使用的组合。 而是将其与黑色和红色进行比较,而可以将其与blackRed进行比较。