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

时间:2020-03-05 18:39:05  来源:igfitidea点击:

我不时看到如下枚举:

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

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

任何人都可以发表很好的解释或者榜样吗?

解决方案

回答

标志允许我们在枚举中使用位掩码。这使我们可以合并枚举值,同时保留指定的值。

[Flags]
public enum DashboardItemPresentationProperties : long
{
    None = 0,
    HideCollapse = 1,
    HideDelete = 2,
    HideEdit = 4,
    HideOpenInNewWindow = 8,
    HideResetSource = 16,
    HideMenu = 32
}

回答

请参见以下示例,以显示声明和潜在用法:

namespace Flags
{
    class Program
    {
        [Flags]
        public enum MyFlags : short
        {
            Foo = 0x1,
            Bar = 0x2,
            Baz = 0x4
        }

        static void Main(string[] args)
        {
            MyFlags fooBar = MyFlags.Foo | MyFlags.Bar;

            if ((fooBar & MyFlags.Foo) == MyFlags.Foo)
            {
                Console.WriteLine("Item has Foo flag set");
            }
        }
    }
}

回答

我们也可以这样做

[Flags]
public enum MyEnum
{
    None   = 0,
    First  = 1 << 0,
    Second = 1 << 1,
    Third  = 1 << 2,
    Fourth = 1 << 3
}

我发现移位比输入4,8,16,32等更容易。它对代码没有影响,因为它们都是在编译时完成的

回答

每当可枚举表示标志的集合而不是单个值时,都应使用flags属性。通常使用按位运算符来操纵此类集合,例如:

myProperties.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,
    Green,
    Red,
    Blue
}

如果以此方式声明,则这些值将为Yellow = 0,Green = 1,Red = 2,Blue =3. 这将使其无法用作标志。

这是正确声明的示例:

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

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

if((myProperties.AllowedColors & MyColor.Yellow) == MyColor.Yellow)
{
    // Yellow has been set...
}

if((myProperties.AllowedColors & MyColor.Green) == MyColor.Green)
{
    // Green has been set...
}

或者,在.NET 4及更高版本中:

if (myProperties.AllowedColors.HasFlag(MyColor.Yellow))
{
    // Yellow has been set...
}

掩护下

之所以可行,是因为我们之前在枚举中使用了2的幂。在幕后,枚举值看起来像这样(表示为字节,具有8位,可以为1或者0)。

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

同样,在将属性AllowedColors设置为红色,绿色和蓝色(其值由管道|进行"或者"的位置)之后,AllowedColors如下所示

myProperties.AllowedColors: 00001110

因此,当我们检索该值时,我们实际上是按位对这些值进行"与"运算

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

无= 0值

并在枚举中使用0,引用msdn:

[Flags]
public enum MyColors
{
    None = 0,
    ....
}
Use None as the name of the flag enumerated constant whose value is zero. You cannot use the None enumerated constant in a bitwise AND operation to test for a flag because the result is always zero. However, you can perform a logical, not a bitwise, comparison between the numeric value and the None enumerated constant to determine whether any bits in the numeric value are set.

我们可以在msdn上找到有关flags属性及其用法以及在msdn上设计标志的更多信息。

回答

添加Mode.Write

Mode = Mode | Mode.Write;

回答

@Nidonocu

要将另一个标志添加到现有值集中,请使用OR赋值运算符。

Mode = Mode.Read;
//Add Mode.Write
Mode |= Mode.Write;
Assert.True(((Mode & Mode.Write) == Mode.Write)
  && ((Mode & Mode.Read) == Mode.Read)));

回答

我最近问类似的事情。

如果使用标志,则可以向枚举添加扩展方法,以更轻松地检查包含的标志(有关详细信息,请参见文章)

这使我们可以执行以下操作:

[Flags]
public enum PossibleOptions : byte
{
    None = 0,
    OptionOne = 1,
    OptionTwo = 2,
    OptionThree = 4,
    OptionFour = 8,

    //combinations can be in the enum too
    OptionOneAndTwo = OptionOne | OptionTwo,
    OptionOneTwoAndThree = OptionOne | OptionTwo | OptionThree,
    ...
}

然后,我们可以执行以下操作:

PossibleOptions opt = PossibleOptions.OptionOneTwoAndThree 

if( opt.IsSet( PossibleOptions.OptionOne ) ) {
    //optionOne is one of those set
}

我发现这比检查包含标志的大多数方法更容易阅读。