[# झंडे] Enum विशेषता सी # में क्या मतलब है?


1445

समय-समय पर मुझे निम्नलिखित की तरह एक दुश्मनी दिखाई देती है:

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

मुझे समझ में नहीं आता है कि वास्तव में [Flags]विशेषता क्या करती है।

किसी के पास एक अच्छी व्याख्या या उदाहरण है जो वे पोस्ट कर सकते हैं?


यह भी ध्यान देने योग्य बात है कि स्वीकृत उत्तर के अलावा, VB.NET को वास्तव में [Flags] की आवश्यकता है - कम से कम .NET लोगों के अनुसार: social.msdn.microsoft.com/forums/en-US/csharplanguage/thread/ ...
रशियो

8
नोट, इन दिनों VB में आवश्यक नहीं है। व्यवहार को C # के रूप में सहेजें - बस ToString () आउटपुट बदलता है। ध्यान दें, आप Enum के बिना तार्किक OR, भी कर सकते हैं। बहुत ही शांत। कैट = 1, डॉग = 2, कैटएडडॉग = कैट || कुत्ता।
चाल्की

14
@Chalky का मतलब है CatAndDog = Cat | Dog(तार्किक या सशर्त के बजाय), मेरा मानना ​​है?
DdW

5
@ डीडब्ल्यू, आंशिक रूप से सही: | इस्तेमाल किया जाना चाहिए, लेकिन | बाइनरी या कहा जाता है। II तार्किक है या (जो शॉर्ट-सर्किटिंग की अनुमति देता है): कम से कम Microsoft के अनुसार?) Msdn.microsoft.com/en-us/library/f355wky8.aspx
Pieter21

जवाबों:


2152

[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] नहीं बनाता है। यदि आप संख्यात्मक मानों को छोड़ देते हैं, तो एनुम काम नहीं करेगा क्योंकि एक बिटवाइज़ ऑपरेशंस में उम्मीद कर सकता है, क्योंकि डिफ़ॉल्ट रूप से मान 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...
}

या .NET 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 को Red, Green और Blue में सेट किया है |, तो AllowedColors इस तरह दिखता है:

myProperties.AllowedColors: 00001110

इसलिए जब आप उस मूल्य को पुनः प्राप्त करते हैं जो आप वास्तव में बिटवाइज़ और &मूल्यों पर कर रहे हैं:

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

कोई नहीं = 0 मान

और 0एमएसएनडीएन से उद्धृत अपने अभिज्ञान के उपयोग के संबंध में :

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

ध्वज के नाम के रूप में किसी का भी उपयोग न करें, जिसका मूल्य शून्य है। आप किसी भी बिटवाइन में एन्युमरेटेड कंटीन्यूअस का उपयोग नहीं कर सकते हैं और किसी झंडे के परीक्षण के लिए ऑपरेशन कर सकते हैं क्योंकि परिणाम हमेशा शून्य होता है। हालाँकि, आप एक तार्किक प्रदर्शन कर सकते हैं, न कि एक बिटवाइज़, संख्यात्मक मान और कोई भी गणना निरंतर के बीच तुलना करने के लिए कि क्या संख्यात्मक मान में कोई बिट सेट हैं।

आप और अधिक झंडे विशेषता के बारे में और जानकारी में इसके उपयोग पा सकते हैं MSDN और MSDN पर झंडे को डिजाइन


156
झंडे खुद कुछ नहीं करते। इसके अलावा, C # को प्रति फ्लैग की आवश्यकता नहीं है। लेकिन ToStringअपने enum के कार्यान्वयन झंडे का उपयोग करता है, और इसलिए करता है Enum.IsDefined, Enum.Parseआदि MyColor.Yellow का परिणाम में झंडे और देखो हटाने की कोशिश करें | MyColor.Red; इसके बिना आपको "5" मिलता है, झंडे के साथ आपको "पीला, लाल" मिलता है। फ्रेमवर्क के कुछ अन्य हिस्से [फ्लैग्स] (जैसे, एक्सएमएल सीरियलाइज़ेशन) का भी उपयोग करते हैं।
रूब

7
// पीला सेट किया गया है ..., मुझे थोड़ा भ्रामक लगता है। कुछ भी सेट नहीं किया गया है, इसका मतलब है कि पीला आपके AllowedColors का सदस्य है, शायद बेहतर होगा // पीले रंग की अनुमति है?
स्कॉट वीवर

48
मैं फॉर्म ए = 1 << 0, B = 1 << 1, C = 1 << 2 ... के स्थिरांक का उपयोग करना पसंद करता हूं ... पढ़ने, समझने, नेत्रहीन जांच करने और बदलने में बहुत आसान है।
निक वेस्टगेट

2
@borrrden, नरक हाँ! मैंने यह पाया: msdn.microsoft.com/en-us/library/system.enum.aspx - "रिमार्क्स" भाग देखें: "Enum .NET फ्रेमवर्क में सभी गणना के लिए आधार वर्ग है।" और "एन्यूमरेशन एनुम से स्पष्ट रूप से विरासत में नहीं मिलता है, इनहेरिटेंस संबंध संकलक द्वारा संभाला जाता है।" इसलिए, जब आप लिखते हैं: सार्वजनिक एनम ब्ला ब्ला ब्ला - यह एक मूल्य प्रकार है। लेकिन, HasFlag विधि चाहती है कि आप उसे System.Enum का एक उदाहरण दें, जो एक वर्ग है (संदर्भ प्रकार :)
अलेक्सी चेपोवोई

2
यदि आप किसी ध्वज को गणन से बाहर करना चाहते हैं, तो X का उपयोग करें, जो कि C # में है। तो अगर आपके पास है myProperties.AllowedColors = MyColor.Red | MyColor.Green | MyColor.Blue;। आप कर सकते हैं:myProperties.AllowedColors = myProperties.AllowedColors ^ MyColor.Blue //myProperties.AllowedColors == MyColor.Red | Mycolor.Green
जोश नं

778

आप यह भी कर सकते हैं

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

मुझे 4,8,16,32 टाइप करने की तुलना में बिट-शिफ्टिंग आसान लगता है। आपके कोड पर इसका कोई प्रभाव नहीं है क्योंकि यह सब संकलन के समय किया गया है


18
यही मेरा मतलब है, मैं स्रोत कोड में पूर्ण अंतर रखना पसंद करता हूं। अगर मेरे पास MyEnum नामक डेटाबेस में एक मेज पर एक स्तंभ है जो किसी एक enums का मान संग्रहीत करता है, और एक रिकॉर्ड 131,072 है, तो मुझे अपने कैलकुलेटर से यह पता लगाने की आवश्यकता होगी कि मान के साथ enum से मेल खाती है << 17। स्रोत में लिखे गए मूल्य 131,072 को देखने के विपरीत।
जेरेमी वीयर

6
@jwg मैं सहमत हूं, यह इस के रनटाइम प्रदर्शन के बारे में अत्यधिक चिंतित होने के लिए मूर्खतापूर्ण है, लेकिन सभी एक ही है, मुझे यह जानकर अच्छा लगता है कि यह कहीं भी आपके द्वारा एनम का उपयोग करने के लिए बिटशिफ्ट्स डालने वाला नहीं है। प्रदर्शन से जुड़ी किसी भी चीज़ के बजाय एक 'वह साफ-सुथरी' चीज है
ओरियन एडवर्ड्स

18
@ जेरेमी वीयर - एक ध्वज गणना मूल्य में कई बिट्स सेट होने जा रहे हैं। तो आपके डेटा विश्लेषण का तरीका अनुचित है। बाइनरी में अपने पूर्णांक मान का प्रतिनिधित्व करने के लिए एक प्रक्रिया चलाएँ। 131,072 [D] = 0000 0000 0000 0000 0000 0000 0000 [B] [32] .. 17 वें बिट सेट के साथ, 1 enum मान असाइन किया गया << 17 आसानी से निर्धारित होता है। 0110 0011 0011 0101 0101 0011 0101 1011 [b] [32] .. enum मान 1 << 31, 1 << 30, 1 << 26, 1 << 25 .. आदि असाइन करते हैं, आदि भी बिना निर्धारित किया जा सकता है। सभी पर एक कैलकुलेटर की सहायता .. जो मुझे संदेह है कि आप बाइनरी प्रतिनिधि प्राप्त किए बिना सभी को निर्धारित करने में सक्षम होंगे।
ब्रेट कैसवेल

13
यह भी इंगित करते हुए कि आप संख्याओं के बजाय सीधे "पिछले" एनम मूल्यों से बिट-शिफ्ट कर सकते हैं, अर्थात Third = Second << 1इसके बजाय Third = 1 << 2- नीचे पूर्ण विवरण देखें
drzaus

26
मैं इस तरह, लेकिन एक बार आप अंतर्निहित enum प्रकार की ऊपरी सीमा पर आते हैं, संकलक जैसे बिट बदलाव के खिलाफ चेतावनी दी है नहीं करता है 1 << 31 == -2147483648, 1 << 32 == 1, 1 << 33 == 2, और इतने पर। इसके विपरीत, यदि आप ThirtySecond = 2147483648एक अंतर प्रकार के लिए कहते हैं , संकलक एक त्रुटि फेंकता है।
आहाटोइनिन

115

संयुक्त उत्तर 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

23
संयोजन एक अच्छी सिफारिश है, लेकिन मुझे लगता है कि जंजीर बिट-शिफ्ट कॉपी और-पेस्ट त्रुटियों जैसे दो = एक << 1, तीन = एक << 1, आदि के लिए प्रवण होगा ... incrementing पूर्णांक पूर्णांक फॉर्म 1 << n सुरक्षित हैं और इरादा साफ है।
रूपर्ट रॉन्सली

2
@RupertRawnsley मेरे जवाब को उद्धृत करने के लिए:> जरूरी नहीं कि यह सिफारिश कर रहा हो, लेकिन सिर्फ आपको इशारा कर सकता है
drzaus

49

कृपया एक उदाहरण के लिए निम्नलिखित देखें जो घोषणा और संभावित उपयोग दिखाता है:

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

यह उदाहरण तब भी काम करता है जब आप बाहर निकलते हैं [झंडे]। यह [झंडे] वाला हिस्सा है जिसके बारे में मैं जानने की कोशिश कर रहा हूं।
गब्री

39

स्वीकृत उत्तर के विस्तार में, C # 7 में बाइनरी लिपि का उपयोग करते हुए एनुम झंडे लिखे जा सकते हैं:

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

मुझे लगता है कि यह प्रतिनिधित्व स्पष्ट करता है कि झंडे के नीचे झंडे कैसे काम करते हैं


2
और सी # 7.2 में यह अग्रणी विभाजक के साथ भी स्पष्ट है ! 0b_0100
विन्केन्ज़ो पेट्रोनिओ

37

मैंने हाल ही में पूछा में कुछ इसी तरह के बारे में ।

यदि आप झंडे का उपयोग करते हैं, तो आप सम्‍मिलित झंडे की जाँच आसान बनाने के लिए एक विस्तार विधि जोड़ सकते हैं (विवरण के लिए पोस्ट देखें)

यह आपको करने की अनुमति देता है:

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

मुझे शामिल किए गए झंडे की जांच करने के सबसे तरीकों से पढ़ने में यह आसान लगता है।


IsSet एक एक्सटेंशन विधि है जिसे मैं मानता हूं?
रॉबर्ट मैकलीन

हाँ - अन्य प्रश्न पढ़ें जिन्हें मैं विवरण के लिए लिंक करता हूं: stackoverflow.com/questions/7244
कीथ

71
.NET 4 HasFlagएन्यूमरेशन्स के लिए एक विधि जोड़ता है , इसलिए आप opt.HasFlag( PossibleOptions.OptionOne )अपने स्वयं के एक्सटेंशन को लिखने के बिना कर सकते हैं
ओरियन एडवर्ड्स

1
ध्यान दें कि बिटवाइज़ ऑपरेशन करने की तुलना HasFlagमें बहुत धीमा है।
वाई हा ली

1
@WaiHaLee आप CodeJam.EnumHelper.IsFlagSet एक्सटेंशन विधि का उपयोग कर सकते हैं, जो कि अभिव्यक्ति का उपयोग करते हुए एक तेज संस्करण में संकलित की गई है: github.com/rsdn/CodeJam/wiki/M_CodeJam_EnumHelper_IsFlagSet__1
NN__

22

@Nidonocu

मानों के मौजूदा सेट में एक और ध्वज जोड़ने के लिए, OR असाइनमेंट ऑपरेटर का उपयोग करें।

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

18

जब मैं झंडे के साथ काम करता हूं तो मैं अक्सर अतिरिक्त कोई नहीं और सभी आइटम घोषित करता हूं। ये जाँचने में मददगार हैं कि सभी झंडे सेट हैं या कोई झंडा सेट नहीं है।

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

सी # 7.0 के बाद से आप द्विआधारी शाब्दिक का उपयोग कर सकते हैं, जो शायद पढ़ने के लिए अधिक सहज हैं:

[Flags] 
enum SuitsFlags { 

    None =     0b0000,

    Spades =   0b0001, 
    Clubs =    0b0010, 
    Diamonds = 0b0100, 
    Hearts =   0b1000,

    All =      0b1111

}


14

if ((x & y) == y)...कंस्ट्रक्शन के बारे में मेरे बारे में कुछ-कुछ वर्बोज़ है , खासकर अगर xऔर yदोनों झंडे के कंपाउंड सेट हैं और आप केवल जानना चाहते हैं कि क्या कोई ओवरलैप है या नहीं।

इस मामले में, आपको वास्तव में यह जानना होगा कि क्या आपके पास बिटमास्क होने के बाद गैर-शून्य मान है [1]

[१] जयम की टिप्पणी देखें। यदि हम प्रामाणिक रूप से बिटकॉम्ब कर रहे थे , तो हमें केवल यह जाँचने की आवश्यकता होगी कि परिणाम सकारात्मक था। लेकिन चूंकि 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();
        }
    }
}

Enum एक हस्ताक्षरित प्रकार पर आधारित हो सकता है, इसलिए आपको "> 0" के बजाय "! = 0" का उपयोग करना चाहिए।
रावेन

@JaimePardos - जब तक हम उन्हें ईमानदार बाइट्स देते हैं, जैसा कि मैं इस उदाहरण में करता हूं, नकारात्मक की कोई अवधारणा नहीं है। सिर्फ 0 से 255. जैसा कि एमएसडीएन चेतावनी देता है , "यदि आप एक नकारात्मक संख्या को एक ध्वजांकित निरंतर के रूप में एक नकारात्मक संख्या को परिभाषित करते हैं तो सावधानी का उपयोग करें क्योंकि ... [कि] आपके कोड को भ्रमित कर सकता है और कोडिंग त्रुटियों को प्रोत्साहित कर सकता है।" "नकारात्मक बिटफ़्लैग" के संदर्भ में सोचना अजीब है! ; ^) मैं थोड़ा और अधिक संपादित करूँगा। लेकिन आप सही हैं, अगर हम अपने में नकारात्मक मूल्यों का उपयोग करते हैं, तो हमें enumजांचने की आवश्यकता होगी != 0
रफिन

10

झंडे आपको अपने गणन के अंदर बिटमास्किंग का उपयोग करने की अनुमति देते हैं। यह आपको गणना मूल्यों को संयोजित करने की अनुमति देता है, जबकि जो निर्दिष्ट हैं उन्हें बनाए रखना।

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

0

माफी अगर कुछ पहले से ही इस परिदृश्य को देखा। झंडे का एक आदर्श उदाहरण हम प्रतिबिंब में देख सकते हैं। हां बाइंडिंग फ्लैग इनम। https://docs.microsoft.com/en-us/dotnet/api/system.reflection.bindingflags?view=netframework-4.8

[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 [] {});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.