سؤال

من وقت لآخر أرى التعداد كما يلي:

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

أنا لا أفهم ماذا بالضبط [Flags]-السمة لا.

أي شخص يكون لديك تفسير جيد أو على سبيل المثال أنها يمكن أن المنصب ؟

هل كانت مفيدة؟

المحلول

على [Flags] سمة ينبغي أن تستخدم كلما enumerable يمثل مجموعة من القيم الممكنة بدلا من قيمة واحدة.هذه المجموعات غالبا ما تستخدم مع جميع المشغلين ، على سبيل المثال:

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] لا تلقائيا جعل التعداد القيم القوى اثنين.إذا قمت بحذف القيم الرقمية ، enum لا تعمل كما قد يتوقع المرء في جميع العمليات ، لأن بشكل افتراضي القيم التي تبدأ مع 0 و الزيادة.

غير صحيحة الإعلان:

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

أو قبل .صافي 4:

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

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

تحت الأغطية

يعمل هذا لأنك تستخدم صلاحيات في التعداد.تحت الأغطية الخاصة بك قيم التعداد تبدو هذه الثنائية الآحاد والأصفار:

 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,
    ....
}

استخدام أي اسم العلم تعداد ثابت قيمته صفر. لا يمكنك استخدام أي تعداد المستمر في المعامل وتشغيل لاختبار العلم لأن النتيجة هي دائما صفر. ومع ذلك ، يمكنك إجراء منطقي وليس أحادي المعامل المقارنة بين قيمة رقمية و لا تعداد مستمرة لتحديد ما إذا كان أي بت في قيمة رقمية يتم تعيين.

يمكنك العثور على مزيد من المعلومات حول أعلام السمة واستخدامه في msdn و تصميم الأعلام في msdn

نصائح أخرى

يمكنك أيضا القيام بذلك

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

أجد بت التحول أسهل من كتابة 4,8,16,32 وهلم جرا.فإنه ليس له أي تأثير على التعليمات البرمجية الخاصة بك لأن كل شيء يتم في وقت الترجمة

الجمع بين إجابات 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

الرجاء راجع ما يلي على سبيل المثال الذي يظهر الإعلان إمكانية الاستخدام:

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");
            }
        }
    }
}

أنا طلب مؤخرا عن شيء مماثل.

إذا كنت تستخدم أعلام يمكنك إضافة ملحق طريقة enums لجعل التحقق الواردة أعلام أسهل (انظر ما بعد لمزيد من التفاصيل)

هذا يسمح لك أن تفعل:

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

أجد هذا أسهل في القراءة من أهم وسائل التحقق شملت الأعلام.

في تمديد قبول الجواب ، في C#7 التعداد أعلام يمكن أن تكون مكتوبة باستخدام ثنائي حرفية:

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

أعتقد أن هذا التمثيل يجعل من الواضح كيف أعلام العمل تحت الأغطية.

@Nidonocu

لإضافة آخر العلم أن القائمة مجموعة من القيم ، استخدام أو عامل التعيين.

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

لإضافة Mode.Write:

Mode = Mode | Mode.Write;

هناك شيء أكثر من اللازم مطول لي عن if ((x & y) == y)... بناء, خاصة إذا x و y هي كل مركب مجموعات من أعلام كنت فقط أريد أن أعرف إذا كان هناك أي التداخل.

في هذه الحالة كل ما يجب معرفته هو إذا كان هناك قيمة غير الصفر[1] بعد أن كنت قد bitmasked.

[1] انظر خايمي تعليق.إذا كنا أصلي bitmasking, كنا تحتاج فقط إلى التحقق من أن النتيجة كانت إيجابية.ولكن منذ enums يمكن أن تكون سلبية, حتى, الغريب, عندما جنبا إلى جنب مع على [Flags] السمة, انها دفاعية إلى رمز != 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();
        }
    }
}

أعلام تسمح لك باستخدام bitmasking داخل التعداد.هذا يسمح لك الجمع بين قيم التعداد ، مع الحفاظ على تلك التي تم تحديدها.

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

عند العمل مع الأعلام كثيرا ما تعلن إضافية أيا وجميع البنود.هذه مفيدة للتحقق ما إذا كان كل شيء يتم تعيين إشارات أو لا العلم هو مجموعة.

[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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top