一尘不染

C# 中的 [Flags] 枚举属性是什么意思?

c#

我不时看到如下枚举:

[Flags]
public enum Options 
{
    None    = 0,
    Option1 = 1,
    Option2 = 2,
    Option3 = 4,
    Option4 = 8
}

我不明白该[Flags]属性到底是做什么的。

任何人都可以发布一个很好的解释或示例吗?


阅读 132

收藏
2022-02-21

共1个答案

一尘不染

[Flags]每当可枚举表示可能值的集合而不是单个值时,都应使用该属性。此类集合通常与按位运算符一起使用,例如:

var allowedColors = MyColor.Red | MyColor.Green | MyColor.Blue;

请注意,该[Flags]属性本身并不能启用此功能 - 它所做的只是允许通过该.ToString()方法进行良好的表示:

enum Suits { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 }
[Flags] enum SuitsFlags { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 }

...

var str1 = (Suits.Spades | Suits.Diamonds).ToString();
           // "5"
var str2 = (SuitsFlags.Spades | SuitsFlags.Diamonds).ToString();
           // "Spades, Diamonds"

还需要注意的是,[Flags] 它不会自动使枚举值成为 2 的幂。如果省略数值,枚举将不会像人们期望的那样在按位运算中工作,因为默认情况下,值从 0 开始并递增。

不正确的声明:

[Flags]
public enum MyColors
{
    Yellow,  // 0
    Green,   // 1
    Red,     // 2
    Blue     // 3
}

如果以这种方式声明,这些值将是 Yellow = 0、Green = 1、Red = 2、Blue = 3。这将使它无法用作标志。

这是正确声明的示例:

[Flags]
public enum MyColors
{
    Yellow = 1,
    Green = 2,
    Red = 4,
    Blue = 8
}

要检索属性中的不同值,可以执行以下操作:

if (myProperties.AllowedColors.HasFlag(MyColor.Yellow))
{
    // Yellow is allowed...
}

或在 .NET 4 之前:

if((myProperties.AllowedColors & MyColor.Yellow) == MyColor.Yellow)
{
    // Yellow is allowed...
}

if((myProperties.AllowedColors & MyColor.Green) == MyColor.Green)
{
    // Green is allowed...
}    

Under the covers

这是有效的,因为您在枚举中使用了 2 的幂。在幕后,您的枚举值在二进制 1 和 0 中看起来像这样:

 Yellow: 00000001
 Green:  00000010
 Red:    00000100
 Blue:   00001000

同样,在使用二进制按位 OR 运算符将属性AllowedColors设置为 Red、Green 和 Blue 后|AllowedColors如下所示:

myProperties.AllowedColors: 00001110

因此,当您检索值时,您实际上是&在对这些值执行按位与:

myProperties.AllowedColors: 00001110
             MyColor.Green: 00000010
             -----------------------
                            00000010 // Hey, this is the same as MyColor.Green!

The None = 0 value

关于0在您的枚举中的使用,引用 MSDN:

[Flags]
public enum MyColors
{
    None = 0,
    ....
}

使用 None 作为值为零的标志枚举常量的名称。您不能在按位与运算中使用 None 枚举常量来测试标志,因为结果始终为零。但是,您可以在数值和 None 枚举常量之间执行逻辑比较,而不是按位比较,以确定数值中是否设置了任何位。

2022-02-21