在C#中[Flags]枚举属性是什么意思?
我不时看到如下枚举:
[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 }
我发现这比检查包含标志的大多数方法更容易阅读。