代码之家  ›  专栏  ›  技术社区  ›  Brian Leahy

在C#中,[Flags]Enum属性意味着什么?

  •  1245
  • Brian Leahy  · 技术社区  · 18 年前

    我不时会看到如下所示的枚举:

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

    [Flags] 属性确实如此。

    11 回复  |  直到 6 年前
        1
  •  2328
  •   Matt Jenkins    7 年前

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

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

    请注意 [旗帜] 属性 单独启用它—它所做的只是允许 .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]
    public enum MyColors
    {
        Yellow,  // 0
        Green,   // 1
        Red,     // 2
        Blue     // 3
    }
    

    如果以这种方式声明,则值将为黄色=0、绿色=1、红色=2、蓝色=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...
    }    
    

    暗中

    这是因为在枚举中使用了二的幂。在封面下,枚举值在二进制1和0中如下所示:

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

    允许的颜色 | 操作人员 允许的颜色

    myProperties.AllowedColors: 00001110
    

    & 关于价值观:

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

    关于使用 0

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

    使用None作为值为零的标志枚举常量的名称。

    有关flags属性及其用法的更多信息,请访问 msdn designing flags at msdn

        2
  •  829
  •   Orion Edwards    12 年前

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

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

        3
  •  126
  •   Community Mohan Dere    9 年前

    https://stackoverflow.com/a/8462/1037948 (通过位移位进行声明)和 https://stackoverflow.com/a/9117/1037948 (在声明中使用组合)可以对以前的值进行位移位,而不是使用数字。不一定推荐,但只是指出你可以。

    而不是:

    [Flags]
    public enum Options : byte
    {
        None    = 0,
        One     = 1 << 0,   // 1
        Two     = 1 << 1,   // 2
        Three   = 1 << 2,   // 4
        Four    = 1 << 3,   // 8
    
        // combinations
        OneAndTwo = One | Two,
        OneTwoAndThree = One | Two | Three,
    }
    

    你可以申报

    [Flags]
    public enum Options : byte
    {
        None    = 0,
        One     = 1 << 0,       // 1
        // now that value 1 is available, start shifting from there
        Two     = One << 1,     // 2
        Three   = Two << 1,     // 4
        Four    = Three << 1,   // 8
    
        // same combinations
        OneAndTwo = One | Two,
        OneTwoAndThree = One | Two | Three,
    }
    

    与LinqPad确认:

    foreach(var e in Enum.GetValues(typeof(Options))) {
        string.Format("{0} = {1}", e.ToString(), (byte)e).Dump();
    }
    

    结果:

    None = 0
    One = 1
    Two = 2
    OneAndTwo = 3
    Three = 4
    OneTwoAndThree = 7
    Four = 8
    
        4
  •  50
  •   Jaider    10 年前

    有关声明和潜在用途的示例,请参见以下内容:

    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");
                }
            }
        }
    }
    
        5
  •  49
  •   Thorkil Holm-Jacobsen    9 年前

    [Flags]
    public enum MyColors
    {
        None   = 0b0000,
        Yellow = 0b0001,
        Green  = 0b0010,
        Red    = 0b0100,
        Blue   = 0b1000
    }
    

    我认为这种表述清楚地表明了旗帜是如何工作的 暗中

        6
  •  41
  •   Community Mohan Dere    9 年前

    asked recently 关于类似的事情。

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

    [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
    }
    

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

        7
  •  30
  •   Jpsy    6 年前

    [Flags] 
    enum SuitsFlags { 
    
        None =     0,
    
        Spades =   1 << 0, 
        Clubs =    1 << 1, 
        Diamonds = 1 << 2, 
        Hearts =   1 << 3,
    
        All =      ~(~0 << 4)
    
    }
    

    用法:

    Spades | Clubs | Diamonds | Hearts == All  // true
    Spades & Clubs == None  // true
    


    2019-10更新:

    由于C#7.0,您可以使用二进制文字,这可能更直观:

    [Flags] 
    enum SuitsFlags { 
    
        None =     0b0000,
    
        Spades =   0b0001, 
        Clubs =    0b0010, 
        Diamonds = 0b0100, 
        Hearts =   0b1000,
    
        All =      0b1111
    
    }
    
        8
  •  23
  •   steve_c    18 年前

    Mode = Mode.Read;
    //Add Mode.Write
    Mode |= Mode.Write;
    Assert.True(((Mode & Mode.Write) == Mode.Write)
      && ((Mode & Mode.Read) == Mode.Read)));
    
        9
  •  18
  •   shA.t Rami Jamleh    10 年前

    Mode.Write :

    Mode = Mode | Mode.Write;
    
        10
  •  15
  •   ruffin    13 年前

    if ((x & y) == y)... 构造,尤其是如果 x y 都是复合标志集,您只想知道是否有 任何 重叠

    在这种情况下,您真正需要知道的是 如果在进行位掩码后存在非零值[1] .

    [1] 见詹姆的评论。如果我们真的 ,我们会 只需检查结果是否为阳性。但是自从 enum s the [Flags] attribute 这是防御性的代码 != 0 而不是 > 0

    基于@andnil的设置进行构建。。。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace BitFlagPlay
    {
        class Program
        {
            [Flags]
            public enum MyColor
            {
                Yellow = 0x01,
                Green = 0x02,
                Red = 0x04,
                Blue = 0x08
            }
    
            static void Main(string[] args)
            {
                var myColor = MyColor.Yellow | MyColor.Blue;
                var acceptableColors = MyColor.Yellow | MyColor.Red;
    
                Console.WriteLine((myColor & MyColor.Blue) != 0);     // True
                Console.WriteLine((myColor & MyColor.Red) != 0);      // False                
                Console.WriteLine((myColor & acceptableColors) != 0); // True
                // ... though only Yellow is shared.
    
                Console.WriteLine((myColor & MyColor.Green) != 0);    // Wait a minute... ;^D
    
                Console.Read();
            }
        }
    }
    
        11
  •  11
  •   Markus Safar    10 年前

    标志允许您在枚举内使用位掩码。这允许您组合枚举值,同时保留指定的枚举值。

    [Flags]
    public enum DashboardItemPresentationProperties : long
    {
        None = 0,
        HideCollapse = 1,
        HideDelete = 2,
        HideEdit = 4,
        HideOpenInNewWindow = 8,
        HideResetSource = 16,
        HideMenu = 32
    }
    
        12
  •  1
  •   bad_coder Singh    5 年前

    如果有人已经注意到这种情况,请道歉。一个完美的例子,旗帜,我们可以看到在反射。对 Binding Flags ENUM .

    [System.Flags]
    [System.Runtime.InteropServices.ComVisible(true)]
    [System.Serializable]
    public enum BindingFlags
    

    用法

    // BindingFlags.InvokeMethod
    // Call a static method.
    Type t = typeof (TestClass);
    
    Console.WriteLine();
    Console.WriteLine("Invoking a static method.");
    Console.WriteLine("-------------------------");
    t.InvokeMember ("SayHello", BindingFlags.InvokeMethod | BindingFlags.Public | 
        BindingFlags.Static, null, null, new object [] {});
    
        13
  •  -4
  •   Mukesh Pareek    5 年前
    • 当可枚举值表示

    • 这里我们使用位运算符、|和&

    •              [Flags]
                   public enum Sides { Left=0, Right=1, Top=2, Bottom=3 }
      
                   Sides leftRight = Sides.Left | Sides.Right;
                   Console.WriteLine (leftRight);//Left, Right
      
                   string stringValue = leftRight.ToString();
                   Console.WriteLine (stringValue);//Left, Right
      
                   Sides s = Sides.Left;
                   s |= Sides.Right;
                   Console.WriteLine (s);//Left, Right
      
                   s ^= Sides.Right; // Toggles Sides.Right
                   Console.WriteLine (s); //Left