Enum अनुमतियों में अक्सर 0, 1, 2, 4 मान क्यों होते हैं?


159

लोग हमेशा ईनम जैसे मूल्यों का उपयोग क्यों कर रहे हैं 0, 1, 2, 4, 8और नहीं 0, 1, 2, 3, 4?

यह बिट संचालन के साथ कुछ करने के लिए है, आदि?

मैं वास्तव में एक छोटे से नमूना स्निपेट की सराहना करूँगा कि यह कैसे सही तरीके से उपयोग किया जाता है :)

[Flags]
public enum Permissions
{
    None   = 0,
    Read   = 1,
    Write  = 2,
    Delete = 4
}


25
मैं डुपे वोट पर असहमत हूं।
zzzzBov

अनुमति सेट करने का UNIX तरीका भी उसी तर्क पर आधारित है।
रूडी

3
@ पास्कल: आपको बिटवाइज़ या (और बिटवाइज़ एंड ) के बारे में पढ़ने में मदद मिल सकती है , जो कि |(और &) प्रतिनिधित्व करती है। विभिन्न उत्तर मान लेते हैं कि आप इससे परिचित हैं।
ब्रायन

2
@ डायपर मैं देख सकता हूं कि आप ऐसा क्यों सोचेंगे, क्योंकि दोनों का उत्तर एक ही है, लेकिन मुझे लगता है कि प्रश्न अलग हैं। अन्य प्रश्न सिर्फ C # में झंडे विशेषता का एक उदाहरण या स्पष्टीकरण के लिए पूछता है। यह प्रश्न बिट झंडे की अवधारणा और उनके पीछे की बुनियादी बातों के बारे में लगता है।
जेरेमी एस

जवाबों:


268

क्योंकि वे दो की शक्तियां हैं और मैं यह कर सकता हूं:

var permissions = Permissions.Read | Permissions.Write;

और शायद बाद में ...

if( (permissions & Permissions.Write) == Permissions.Write )
{
    // we have write access
}

यह एक बिट फ़ील्ड है, जहां प्रत्येक सेट बिट कुछ अनुमति से मेल खाता है (या जो भी गणना की गई है वह तार्किक रूप से मेल खाती है)। यदि इन्हें परिभाषित किया गया है 1, 2, 3, ...तो आप इस तरीके से बिटकॉइन ऑपरेटरों का उपयोग नहीं कर पाएंगे और सार्थक परिणाम प्राप्त कर सकते हैं। गहरा करने के लिए ...

Permissions.Read   == 1 == 00000001
Permissions.Write  == 2 == 00000010
Permissions.Delete == 4 == 00000100

एक पैटर्न यहाँ देखें? अब अगर हम अपना मूल उदाहरण लेते हैं,

var permissions = Permissions.Read | Permissions.Write;

फिर...

permissions == 00000011

देख? दोनों Readऔर Writeबिट्स सेट हैं, और मैं इसे स्वतंत्र रूप से जांच सकता हूं (यह भी देखें कि Deleteबिट सेट नहीं है और इसलिए यह मान हटाने की अनुमति नहीं देता है)।

यह एक बिट के एक क्षेत्र में कई झंडे को संग्रहीत करने की अनुमति देता है।


2
@ माल्कम: यह करता है; myEnum.IsSet। मेरा विचार है कि यह एक पूरी तरह से बेकार अमूर्तता है और केवल टाइपिंग में कटौती करने के लिए कार्य करता है, लेकिन meh
Ed S.

1
अच्छा जवाब है, लेकिन आपको यह उल्लेख करना चाहिए कि झंडे की विशेषता क्यों लागू की गई है, और जब आप झंडे को कुछ एनमों पर भी लागू नहीं करना चाहेंगे।
एंडी

3
@Andy: दरअसल, यह Flagsविशेषता आपको irc सुंदर प्रिंटिंग ’ आई सर्किल से कुछ ज्यादा ही देती है। आप गुण की उपस्थिति की परवाह किए बिना ध्वज के रूप में एक गणना मूल्य का उपयोग कर सकते हैं।
एड एस।

3
@ डाइट: क्योंकि यदि C # में स्टेटमेंट के लिए बूलियन एक्सप्रेशन की आवश्यकता होती है। 0नहीं है false; falseहै false। हालाँकि आप लिख सकते हैं if((permissions & Permissions.Write) > 0)
एड एस।

2
'मुश्किल' के बजाय (permissions & Permissions.Write) == Permissions.Write, अब आप उपयोग कर सकते हैंenum.HasFlag()
लुई कोट्टमन

147

यदि यह अभी भी अन्य उत्तरों से स्पष्ट नहीं है, तो इसके बारे में इस तरह सोचें:

[Flags] 
public enum Permissions 
{   
   None = 0,   
   Read = 1,     
   Write = 2,   
   Delete = 4 
} 

लिखने का एक छोटा तरीका है:

public enum Permissions 
{   
    DeleteNoWriteNoReadNo = 0,   // None
    DeleteNoWriteNoReadYes = 1,  // Read
    DeleteNoWriteYesReadNo = 2,  // Write
    DeleteNoWriteYesReadYes = 3, // Read + Write
    DeleteYesWriteNoReadNo = 4,   // Delete
    DeleteYesWriteNoReadYes = 5,  // Read + Delete
    DeleteYesWriteYesReadNo = 6,  // Write + Delete
    DeleteYesWriteYesReadYes = 7, // Read + Write + Delete
} 

आठ संभावनाएँ हैं, लेकिन आप केवल चार सदस्यों के संयोजन के रूप में उनका प्रतिनिधित्व कर सकते हैं। यदि सोलह संभावनाएँ थीं तो आप उन्हें केवल पाँच सदस्यों के संयोजन के रूप में प्रस्तुत कर सकते हैं। यदि चार बिलियन संभावनाएँ थीं तो आप केवल 33 सदस्यों के संयोजन के रूप में उनका प्रतिनिधित्व कर सकते थे! स्पष्ट रूप से केवल 33 सदस्यों का होना बेहतर है, प्रत्येक (शून्य को छोड़कर) दो की एक शक्ति, एक एनुम में चार अरब वस्तुओं का नाम देने की कोशिश करने के लिए।


32
enumचार अरब सदस्यों के साथ मानसिक छवि के लिए +1 । और दुखद बात यह है कि, शायद किसी ने वहाँ कोशिश की है।
डैनियल प्रीडन

23
@DanielPryden डेली डब्ल्यूटीएफ के दैनिक पाठक के रूप में, मुझे विश्वास है।
शराबी

1
2 ^ 33 = ~ 8.6 बिलियन। 4 बिलियन विभिन्न मूल्यों के लिए आपको केवल 32 बिट्स की आवश्यकता होती है।
सीवीएन

5
@ माइकलकॉर्जलिंग 33 में से एक 0 डिफ़ॉल्ट के लिए है
शाफ़्ट फ्रीक

@ माइकलकॉर्जलिंग: निष्पक्ष होने के लिए, केवल 32 सदस्य हैं जो 2 की शक्तियां हैं, क्योंकि 0 दो की शक्ति नहीं है। इसलिए "33 सदस्य, प्रत्येक एक दो की एक शक्ति" ठीक से सही नहीं है (जब तक कि आप 2 ** -infinityदो की शक्ति के रूप में गिनती नहीं करते हैं )।
ब्रायन

36

क्योंकि ये मान बाइनरी में अद्वितीय बिट स्थानों का प्रतिनिधित्व करते हैं:

1 == binary 00000001
2 == binary 00000010
4 == binary 00000100

इत्यादि

1 | 2 == binary 00000011

संपादित करें:

3 == binary 00000011

बाइनरी में 3 का प्रतिनिधित्व 1 वाले स्थान और टॉस जगह दोनों में 1 के मान से किया जाता है। यह वास्तव में मूल्य के समान है 1 | 2। इसलिए जब आप किसी राज्य का प्रतिनिधित्व करने के लिए झंडे के रूप में द्विआधारी स्थानों का उपयोग करने की कोशिश कर रहे हैं, तो 3 आमतौर पर सार्थक नहीं होता है (जब तक कि कोई तार्किक मूल्य नहीं है कि वास्तव में दो का संयोजन है)

आगे के स्पष्टीकरण के लिए, आप अपने उदाहरण का विस्तार इस प्रकार करना चाहते हैं:

[Flags]
public Enum Permissions
{
  None = 0,   // Binary 0000000
  Read = 1,   // Binary 0000001
  Write = 2,  // Binary 0000010
  Delete = 4, // Binary 0000100
  All = 7,    // Binary 0000111
}

इसलिए में मेरे पास है Permissions.All, मैं भी परोक्ष है Permissions.Read, Permissions.WriteऔरPermissions.Delete


और 2 | 3 के साथ क्या समस्या है?
पास्कल

1
@Pascal: क्योंकि 3है 11द्विआधारी, यानी, यह एक सेट बिट करने के लिए नक्शे नहीं है तो आप एक सार्थक मूल्य के लिए एक मनमाना स्थिति में 1 बिट मैप करने के लिए क्षमता खो देते हैं।
एड एस।

8
@Pascal दूसरे शब्दों में कहें, 2|3 == 1|3 == 1|2 == 3। तो अगर आप द्विआधारी के साथ एक मूल्य है 00000011, और अपने झंडे मूल्यों शामिल 1, 2, और 3, तो तुम अगर है कि मूल्य का प्रतिनिधित्व करता है पता नहीं होगा 1 and 3, 2 and 3, 1 and 2या only 3। जो इसे बहुत कम उपयोगी बनाता है।
यशवित

10
[Flags]
public Enum Permissions
{
    None   =    0; //0000000
    Read   =    1; //0000001
    Write  = 1<<1; //0000010
    Delete = 1<<2; //0000100
    Blah1  = 1<<3; //0001000
    Blah2  = 1<<4; //0010000
}

मुझे लगता है कि इस तरह से लिखना समझना और पढ़ना आसान है, और आपको इसकी गणना करने की आवश्यकता नहीं है।


5

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

[Flags]
public Enum Permissions
{
  None =  0x00,
  Read =  0x01,
  Write = 0x02,
  Delete= 0x04,
  Blah1 = 0x08,
  Blah2 = 0x10
}

4
@ पास्कल: शायद इस समय यह आपके लिए अधिक पठनीय है, लेकिन जैसा कि आप अनुभव करते हैं कि हेक्स में बाइट्स देखने का अनुभव है। हेक्स मैप्स में दो अंक एक बाइट मैप्स में 8 बिट्स (खैर ... एक बाइट आमतौर पर 8 बिट्स वैसे भी होता है ... हमेशा सच नहीं होता है, लेकिन इस उदाहरण के लिए यह सामान्य है)।
एड एस।

5
@ त्वरित, जब आप 41943042 से गुणा करते हैं तो आपको क्या मिलता है ? कैसे के बारे में 0x400000? 0x800000सही उत्तर की तुलना 8388608में इसे पहचानना बहुत आसान है , और यह हेक्स मान टाइप करने के लिए कम त्रुटि वाला भी है।
फोग

6
एक नज़र में, अगर आपके झंडे ठीक से सेट किए गए हों (यानी, 2 की शक्तियां हैं), अगर आप हेक्स का उपयोग करते हैं, तो यह बताना बहुत आसान है। है 0x10000दोनों में से एक शक्ति? हां, यह 1, 2, 4 या 8 से शुरू होता है और इसके बाद सभी 0s हैं। आपको 0x10 से 16 तक मानसिक रूप से अनुवाद करने की आवश्यकता नहीं है (हालांकि ऐसा करने से शायद दूसरी प्रकृति बन जाएगी), बस इसे "2 की कुछ शक्ति" के रूप में सोचें।
ब्रायन

1
मैं पूरी तरह से जारेड के साथ हूं, यह हेक्स में नोट करना बहुत आसान है। तुम सिर्फ का उपयोग 1 2 4 से 8 और पाली
bevacqua

1
व्यक्तिगत रूप से, मैं सिर्फ P_READ = 1 << 0, P_WRITE = 1 <, 1, P_RW = P_READ | P_WRITE का उपयोग करना पसंद करता हूं। मुझे यकीन नहीं है कि अगर उस तरह की निरंतर-तह सी # में काम करती है, लेकिन यह सी / सी ++ (साथ ही जावा, मुझे लगता है) में ठीक काम करती है।
शराबी

1

यह वास्तव में एक टिप्पणी का अधिक है, लेकिन चूंकि यह स्वरूपण का समर्थन नहीं करेगा, मैं सिर्फ एक विधि को शामिल करना चाहता था जिसे मैंने ध्वज गणना स्थापित करने के लिए नियोजित किया है:

[Flags]
public enum FlagTest
{
    None = 0,
    Read = 1,
    Write = Read * 2,
    Delete = Write * 2,
    ReadWrite = Read|Write
}

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

ध्यान दें, हालांकि, एक बार किसी भी उत्पादन प्रणाली के लिए एक समाधान प्रकाशित किया जाता है (खासकर अगर एनम एक तंग युग्मन के बिना उजागर होता है, जैसे कि एक वेब सेवा पर), तो यह एनम के भीतर किसी भी मौजूदा मूल्य को बदलने के खिलाफ अत्यधिक उचित है।


1

लॉट इस के लिए अच्छे जवाब ... मैं सिर्फ इतना कहूंगा .. अगर आपको पसंद नहीं है, या आसानी से समझ नहीं सकता है कि <<वाक्यविन्यास क्या व्यक्त करने की कोशिश कर रहा है .. मैं व्यक्तिगत रूप से एक विकल्प पसंद करता हूं (और कहने की हिम्मत करता हूं, सीधे शब्दों में घोषणा की शैली) ...

typedef NS_OPTIONS(NSUInteger, Align) {
    AlignLeft         = 00000001,
    AlignRight        = 00000010,
    AlignTop          = 00000100,
    AlignBottom       = 00001000,
    AlignTopLeft      = 00000101,
    AlignTopRight     = 00000110,
    AlignBottomLeft   = 00001001,
    AlignBottomRight  = 00001010
};

NSLog(@"%ld == %ld", AlignLeft | AlignBottom, AlignBottomLeft);

LOG 513 == 513

इतना आसान (खुद के लिए, कम से कम) समझने के लिए। अप लाइन अप करें… आप जिस परिणाम की इच्छा करें उसका वर्णन करें, परिणाम प्राप्त करें जो आप चाहते हैं .. आवश्यक नहीं “गणना”।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.