【问题标题】:How does c# flags attribute enum bit combining work?c# flags 属性枚举位组合如何工作?
【发布时间】:2019-06-30 08:09:28
【问题描述】:

枚举的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

但是,如果我将另一个成员添加到“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 是“Lime, Green”,而不是之前的“Black, Red, Green”
等等

我知道这是一种不好的做法,但我想知道编译器如何决定将哪些成员组合用于某个位组合?

【问题讨论】:

  • 这里的方法很简单;它首先查找完全匹配,然后查找具有相同值的按位组合;但是 - 这很重要 - 认为 3===Lime 作为一种颜色是非常错误的;您实际上所做的是将“Lime”定义为Black/Red 组合的别名。按位数学用 [Flags] 统治一天。还有青柠===3===(1|2)===(黑|红)。
  • 旁注:4 绝对不是“石灰,黑色”; "Lime, Black" 将是 3|1,即 3,而不是 4;组合标志时不要添加;你或(按位)
  • @MarcGravell 您的评论实际上是最好的答案。至于旁注:D'oh!当然你是对的,它只是让我忘记了。 :)

标签: c# enums bit-manipulation bitflags


【解决方案1】:

这与禁止或允许组合或按位运算符(无论有无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,这是表示所有这三个值的便捷方式标志已设置。

【讨论】:

  • (顺便说一句,许多旧计算机系统具有 3 位 RGB 颜色,正如此处示例枚举的工作原理一样,而其他一些系统具有 4 位 RGBI 颜色,增加了另一位亮度,“深白色”和“浅黑色”是灰色阴影)。
【解决方案2】:

如果你写成二进制你可以看到。

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

所以 3 不是石灰,它应该是 blackRed。 3是黑色和红色。您不仅可以设置 2 的幂,以便更轻松地使用组合。 相反,与黑色和红色相比,您可以与 blackRed 进行比较。

【讨论】:

    猜你喜欢
    • 2010-09-05
    • 2019-02-16
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-04
    • 1970-01-01
    • 2011-12-15
    相关资源
    最近更新 更多