क्या एनम को 0 या 1 से शुरू करना चाहिए?


136

कल्पना कीजिए कि मैंने निम्नलिखित एनम को परिभाषित किया है:

public enum Status : byte
{
    Inactive = 1,
    Active = 2,
}

एनम का उपयोग करने के लिए सबसे अच्छा अभ्यास क्या है? क्या इसे 1उपरोक्त उदाहरण के साथ शुरू करना चाहिए या 0इस तरह (स्पष्ट मूल्यों के बिना) के साथ शुरू करना चाहिए :

public enum Status : byte
{
    Inactive,
    Active
}

13
क्या आपको वास्तव में उन्हें स्पष्ट रूप से संख्या देने की आवश्यकता है?
युक

164
Enums सिर्फ इसलिए बनाए गए थे ताकि इस तरह की चीजें महत्वपूर्ण न हों।
BoltClock

9
@ डैनियल - अरे नहीं! एनम का उपयोग करने के लिए बेहतर है जब आपको लगता है कि एक बुलियन का उपयोग करने की तुलना में एक बुलियन करेगा जब आप एक एनम के बारे में सोच रहे हैं।
AAT

22
FileNotFound मूल्य के कारण @ डैनियल, बेशक
Joubarc

5
xkcd.com/163 सरणी सूचकांकों की तुलना में कहीं अधिक बेहतर करने के लिए लागू होता है।
लेफ्टनैबाउटआउट

जवाबों:


161

फ्रेमवर्क डिजाइन दिशानिर्देश :

Ums सरल शब्दों पर शून्य का मान प्रदान करते हैं।

"कुछ भी नहीं" जैसे मूल्य को कॉल करने पर विचार करें। यदि इस विशेष एनम के लिए ऐसा मान उचित नहीं है, तो एनम के लिए सबसे सामान्य डिफ़ॉल्ट मान को शून्य का अंतर्निहित मान सौंपा जाना चाहिए।

फ्रेमवर्क डिज़ाइन दिशानिर्देश / डिज़ाइनिंग फ्लैग एनम :

Unless शून्य मान के ध्वज एनुम का उपयोग करके AVOID जब तक कि मूल्य "सभी झंडे साफ किए जाते हैं" का प्रतिनिधित्व करता है और उचित रूप से नामित किया जाता है, जैसा कि अगली दिशानिर्देश द्वारा निर्धारित किया गया है।

Ums फ्लैग एनमों का शून्य मान किसी के नाम पर न रखें। एक ध्वज एनुम के लिए, मान का हमेशा मतलब होना चाहिए "सभी झंडे साफ हो गए हैं।"


28
जल्दी विफल: यदि 'कोई नहीं' उचित नहीं है, लेकिन कोई तार्किक डिफ़ॉल्ट मान नहीं है, तो मैं अभी भी शून्य का मान रखूंगा (और इसे 'कोई नहीं' या 'अमान्य' कहूंगा) जिसका उपयोग करने का मतलब नहीं है, बस इतना यदि उस गणना के एक वर्ग के सदस्य को ठीक से आरम्भ नहीं किया गया है, तो असंगठित मूल्य आसानी से देखा जा सकता है, और switchबयानों में यह उस defaultखंड पर कूद जाएगा , जहाँ मैं फेंक देता हूँ InvalidEnumArgumentException। अन्यथा एक कार्यक्रम अनायास ही शून्य मान के साथ चलना जारी रख सकता है, जो वैध हो सकता है और किसी का ध्यान नहीं जा सकता है।
एलियन गुरिलनेक

1
@ सभी को केवल यह पता होना बेहतर है कि आपके द्वारा पता किए गए मानों को मान्य हैं और फिर सेटर और / या कंस्ट्रक्टर में अमान्य मानों की जाँच करें। इस तरह आपको तुरंत पता चल जाता है कि कुछ कोड किसी अज्ञात समय के लिए मौजूद डेटा के साथ किसी ऑब्जेक्ट को अनुमति देने के बजाय सही तरीके से काम नहीं कर रहे हैं या बाद में इसके बारे में पता लगा रहे हैं। जब तक 'कोई नहीं' एक मान्य स्थिति का प्रतिनिधित्व करता है, आपको इसका उपयोग नहीं करना चाहिए।
wprl

@SoloBold: यह एक ऐसे मामले की तरह लगता है, जहां आप एक कंस्ट्रक्टर में एनम वर्ग के सदस्य को इनिशियलाइज़ करना नहीं भूलते। यदि आप प्रारंभ करना या मान्य करना भूल जाते हैं, तो सत्यापन की कोई भी राशि आपकी सहायता नहीं करेगी। इसके अलावा, सरल डीटीओ कक्षाएं हैं जिनके पास कोई भी निर्माता नहीं है, लेकिन इसके बजाय ऑब्जेक्ट आरंइज़र पर निर्भर हैं । ऐसे बग का शिकार करना बेहद दर्दनाक हो सकता है। फिर भी, अप्रयुक्त संचय मूल्य को जोड़ना एक बदसूरत एपीआई के लिए बनाता है। मैं सार्वजनिक खपत के लिए तैयार एपीआई के लिए इसे टालूंगा।
एलोन गुरिलनेक

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

@SoloBold: 15 ऑटो-कार्यान्वित गुणों के साथ एक डीटीओ वर्ग की कल्पना करें। इसकी बॉडी 15 लाइन लंबी है। अब नियमित गुणों के साथ उसी वर्ग की कल्पना करें। किसी भी सत्यापन तर्क को जोड़ने से पहले वह न्यूनतम 180 रेखाएँ हैं। यह वर्ग केवल डेटा-ट्रांसफर उद्देश्यों के लिए आंतरिक रूप से उपयोग किया जाता है। आप कौन सी जगह बनाए रखेंगे, 15 लाइन क्लास या 180+ लाइन क्लास? सक्सेसनेस का अपना मूल्य है। लेकिन फिर भी, हमारी दोनों शैलियाँ सही हैं, वे बस अलग हैं। (मुझे लगता है कि यह वह जगह है जहां AOP तर्क के दोनों पक्षों में स्वीप करता है और जीतता है)।
एलोन गुरिलनेक

66

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


9
+1, सहमत है, लेकिन केवल उस स्थिति में जहां आपका कोड किसी बाहरी कारण (जैसे क्रमांकन) के पूर्णांक पर निर्भर करता है। हर जगह आपको केवल यह काम करने की रूपरेखा देने के साथ रहना चाहिए। यदि आप आंतरिक रूप से पूर्णांक मानों पर भरोसा करते हैं, तो आप शायद कुछ गलत कर रहे हैं (देखें: फ्रेमवर्क इसे काम करने दें)।
मैथ्यू शारले

3
मुझे एनम का पाठ जारी रखना पसंद है। डेटाबेस को और अधिक प्रयोग करने योग्य बनाता है।
डेव

2
आम तौर पर, आपको स्पष्ट रूप से मूल्यों को निर्धारित करने की आवश्यकता नहीं होती है ... तब भी जब वे क्रमबद्ध हो जाते हैं। बस हमेशा अंत में नए मूल्यों को जोड़ते हैं। यह क्रमिक समस्याओं को हल करेगा। अन्यथा आपको अपने डेटा स्टोर के एक संस्करण की आवश्यकता हो सकती है (उदाहरण के लिए / रीडिंग / मान लिखते समय व्यवहार बदलने के लिए एक संस्करण वाला एक फ़ाइल हेडर) (या स्मृति पैटर्न देखें)
Beachwalker

4
@ डव: जब तक आप यह पता नहीं लगाते हैं कि एनुम ग्रंथ पवित्र हैं, तब तक आप अपने आप को असफल होने के लिए तैयार कर लेते हैं, यदि भविष्य का प्रोग्रामर किसी नाम को स्पष्ट करने या कुछ नामकरण परंपरा के अनुरूप समायोजित करने का फैसला करता है।
सुपरकैट

1
@pstrjds: यह एक शैलीगत व्यापार है जो मुझे लगता है - डिस्क स्थान सस्ता है, हालांकि, समय लगातार ईनम मानों के बीच परिवर्तित करने में खर्च किया जाता है और एक खोज डीबी को खोजने के लिए अपेक्षाकृत महंगा होता है (दोगुना इसलिए यदि आपके पास डेटाबेस के खिलाफ रिपोर्टिंग टूल सेटअप है या कुछ इसी तरह) । यदि आप abotu स्थान से चिंतित हैं, तो नए SQL सर्वर संस्करणों के साथ आपके पास एक डेटाबेस संपीड़ित हो सकता है, जिसका अर्थ है कि "SomeEnumTextualValue" की 1000 घटनाएं मुश्किल से किसी भी अधिक स्थान का उपयोग करेंगी। बेशक यह सभी परियोजनाओं के लिए काम नहीं करेगा - यह एक व्यापार बंद है। मुझे लगता है कि बैंडविड्थ के बारे में चिंता समय से पहले अनुकूलन की तरह बदबू आ रही है, शायद!
डेव

15

एक Enum एक मान प्रकार है और इसका डिफ़ॉल्ट मान (उदाहरण के लिए एक वर्ग में Enum फ़ील्ड के लिए) 0 होगा यदि स्पष्ट रूप से प्रारंभ नहीं किया गया है।

इसलिए आप आम तौर पर एक परिभाषित स्थिरांक (जैसे अज्ञात) के रूप में 0 चाहते हैं।

आपके उदाहरण में, यदि आप Inactiveडिफ़ॉल्ट होना चाहते हैं , तो इसका मान शून्य होना चाहिए। अन्यथा आप एक स्थिरांक जोड़ने पर विचार करना चाह सकते हैं Unknown

कुछ लोगों ने सिफारिश की है कि आप अपने स्थिरांक के लिए मूल्यों को स्पष्ट रूप से निर्दिष्ट नहीं करते हैं। ज्यादातर मामलों में शायद अच्छी सलाह, लेकिन कुछ मामले हैं जब आप ऐसा करना चाहेंगे:

  • झांकियां

  • ऐसे एनम जिसका मान बाहरी सिस्टम (जैसे COM) के साथ इंटरोप में उपयोग किया जाता है।


मैंने पाया है कि जब आप स्पष्ट रूप से मूल्यों को निर्धारित नहीं करते हैं तो झंडे वाले एनम बहुत अधिक पठनीय होते हैं । - कंपाइलर को आपके लिए बाइनरी गणित करने देने के लिए कम त्रुटि वाला तरीका भी। (यानी [Flags] enum MyFlags { None = 0, A, B, Both = A | B, /* etc. */ }जिस तरह से अधिक पठनीय है, की तुलना में [Flags] enum MyFlags { None = 0, A = 1, B = 2, Both = 3, /* etc */ }।)
BrainSlugs83

1
@ BrainSlugs83 - मैं यह नहीं देखता कि सामान्य स्थिति में यह कैसे सहायक होगा - उदाहरण के [Flags] enum MyFlags { None=0, A, B, C } लिए परिणाम होगा [Flags] enum MyFlags { None=0, A=1, B=2, C=3 }, जबकि एक झंडे के लिए आप आमतौर पर C = 4 चाहते हैं।
जो

14

जब तक आपके पास इसे बदलने का कोई विशिष्ट कारण नहीं है, तब तक अपने डिफ़ॉल्ट मानों के साथ एनम को छोड़ दें, जो शून्य पर शुरू होता है।

public enum Status : byte
{
    Inactive,
    Active
}

6

मैं कहूंगा कि सबसे अच्छा अभ्यास उन्हें नंबर नहीं देना है और इसे निहित होने देना है - जो कि 0. से शुरू होगा। इसके निहितार्थ के बाद से इसकी भाषा वरीयता है जो हमेशा अनुसरण करने के लिए अच्छा है :)


6

मैं 0 से बूलियन टाइप एनम शुरू करूंगा।

जब तक "निष्क्रिय" का अर्थ "निष्क्रिय" के अलावा कुछ और नहीं है :)

यह उन लोगों के लिए मानक बनाए रखता है।


6

मैं कहूंगा, यह इस बात पर निर्भर करता है कि आप उनका उपयोग कैसे करते हैं। एनुम को फ़्लैग करने के लिए None, मान के लिए 0 होना एक अच्छा अभ्यास है , जैसे:

[Flags]
enum MyEnum
{
    None = 0,
    Option1 = 1,
    Option2 = 2,
    Option3 = 4,
    All = Option1 | Option2 | Option3,
}

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

अन्य मामलों में मैं इसे वैसे ही छोड़ दूंगा, जैसे कोई परवाह नहीं कि वे 0 या 1 से शुरू करते हैं।


5

जब तक आप कच्चे मूल्यों का उपयोग करने के लिए एक अच्छा कारण है, तो आप केवल कभी अंतर्निहित मानों का उपयोग करते हैं और उनके साथ संदर्भित किया जाना चाहिए Status.Activeऔर Status.Inactive

पकड़ यह है कि आप एक फ्लैट फाइल या डीबी में डेटा स्टोर करना चाहते हैं, या एक फ्लैट फाइल या डीबी का उपयोग कर सकते हैं जो किसी और ने बनाई है। यदि आप इसे स्वयं बना रहे हैं, तो इसे बनाएं ताकि नंबर फिट बैठता है कि एनम किस लिए उपयोग किया जाता है।

यदि डेटा आपका नहीं है, तो निश्चित रूप से आप वह उपयोग करना चाहते हैं जो मूल देव ने नंबरिंग स्कीम के रूप में उपयोग किया था।

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

enum Example
{
  None      = 0,            //  0
  Alpha     = 1 << 0,       //  1
  Beta      = 1 << 1,       //  2
  Gamma     = 1 << 2,       //  4
  Delta     = 1 << 3,       //  8
  Epsilon   = 1 << 4,       // 16
  All       = ~0,           // -1
  AlphaBeta = Alpha | Beta, //  3
}

मान दो की शक्तियां होनी चाहिए और बिट-शिफ्ट ऑपरेशन का उपयोग करके व्यक्त की जा सकती है। None, स्पष्ट रूप से होना चाहिए 0, लेकिन Allस्पष्ट रूप से कम है -1~0एक बाइनरी नकार है 0और एक संख्या में परिणाम है जिसके पास हर बिट सेट है 1, जो के मान का प्रतिनिधित्व करता है-1 । मिश्रित झंडे के लिए (अक्सर सुविधा के लिए उपयोग किया जाता है) अन्य मानों को बिटवाइज़ या ऑपरेटर का उपयोग करके विलय किया जा सकता है |


3

कोई भी संख्या निर्दिष्ट न करें। बस इसे वैसे ही इस्तेमाल करें जैसे इसे इस्तेमाल किया जाना चाहिए।


3

यदि निर्दिष्ट क्रमांक 0 से शुरू नहीं होता है।

यह स्पष्ट होना महत्वपूर्ण है क्योंकि एनमों को अक्सर क्रमबद्ध और एक इंट के रूप में संग्रहीत किया जाता है, न कि एक स्ट्रिंग के रूप में।

डेटाबेस में संग्रहीत किसी भी एनम के लिए, हम हमेशा रखरखाव के दौरान स्थानांतरण और पुन: असाइनमेंट को रोकने के लिए विकल्पों को स्पष्ट रूप से संख्या देते हैं।

Microsoft के अनुसार, अनुशंसित कन्वेंशन एक अनैतिक या सबसे सामान्य डिफ़ॉल्ट मान का प्रतिनिधित्व करने के लिए पहले शून्य विकल्प का उपयोग करता है।

नीचे 0 के बजाय 1 पर नंबर शुरू करने का एक शॉर्टकट है।

public enum Status : byte
{
    Inactive = 1,
    Active
}

यदि आप एनम मानों पर बिट ऑपरेटरों का उपयोग करने के लिए ध्वज मान सेट करना चाहते हैं, तो शून्य मान पर नंबरिंग शुरू न करें।


2

यदि आप 1 से शुरू करते हैं, तो आप आसानी से अपनी चीजों की गिनती प्राप्त कर सकते हैं।

{
    BOX_THING1     = 1,
    BOX_THING2     = 2,
    BOX_NUM_THING  = BOX_THING2
};

यदि आप 0 से शुरू करते हैं, तो पहले एक का उपयोग असमान चीजों के लिए मूल्य के रूप में करें।

{
    BOX_NO_THING   = 0,
    BOX_THING1     = 1,
    BOX_THING2     = 2,
    BOX_NUM_THING  = BOX_THING2
};

5
क्षमा करें, जोनाथन। मुझे लगता है, यह सुझाव मेरे दिमाग में थोड़ा "पुराना स्कूल" है (इस तरह का सम्मेलन निम्न-स्तर-सी वर्षों से आता है)। यह एनम के बारे में कुछ अतिरिक्त जानकारी को "एम्बेड" करने के लिए एक त्वरित समाधान के रूप में ठीक है लेकिन यह बड़ी प्रणालियों में एक अच्छा अभ्यास नहीं है। यदि आपको उपलब्ध मानों आदि की संख्या और BOX_NO_THING1 के बारे में जानकारी की आवश्यकता है, तो आपको एक एनम का उपयोग नहीं करना चाहिए? क्या आप उसे BOX_NO_THING + 1 देंगे? एनम का उपयोग किया जाना चाहिए जैसा कि वे उपयोग करने के लिए हैं: "बोल" नामों द्वारा दर्शाए गए विशिष्ट (इंट) मान।
समुद्र तट

हम्म। आप यह मानकर चल रहे हैं कि यह पुराना स्कूल है क्योंकि मैंने सभी कैप्स का इस्तेमाल किया था, मुझे लगता है कि MicrosoftBumpyCaseWithLongNames के बजाय। हालांकि मैं मानता हूं कि एन्यूज़ XyzNumDefsInMyEnum परिभाषा तक पहुंचने तक पुनरावृत्तियों का उपयोग लूप से करना बेहतर है।
जोनाथन क्लाइन IEEE

यह विभिन्न तरीकों से C # में भयानक अभ्यास है। अब जब आप अपने एनमों की गिनती सही तरीके से करने के लिए जाते हैं, या यदि आप उन्हें सही तरीके से गणना करने का प्रयास करते हैं, तो आपको एक अतिरिक्त, डुप्लिकेट ऑब्जेक्ट मिलेगा। इसके अलावा यह .ToString () को अन्य चीजों के बीच संभावित अस्पष्ट (आधुनिक क्रमांकन को खराब करना) कहता है।
BrainSlugs83

0

सबसे पहले, जब तक आप किसी कारण के लिए विशिष्ट मान निर्दिष्ट नहीं कर रहे हैं (संख्यात्मक मान का अर्थ कहीं और है, अर्थात डेटाबेस या बाहरी सेवा) तब संख्यात्मक मान बिल्कुल निर्दिष्ट न करें और उन्हें स्पष्ट होने दें।

सभी में से दूसरा, आपको हमेशा एक शून्य मूल्य आइटम (गैर-फ़्लैग एनम में) होना चाहिए। उस तत्व का उपयोग डिफ़ॉल्ट मान के रूप में किया जाएगा।


0

जब तक कोई कारण न हो, तब तक उन्हें प्रारंभ न करें, जैसे कि किसी सरणी या सूची में सूचक के रूप में उनका उपयोग करना, या यदि कोई अन्य व्यावहारिक कारण हो (जैसे कि बिटवाइज़ संचालन में उनका उपयोग करना)।

आपकी enumठीक वही शुरुआत होनी चाहिए, जहां इसकी जरूरत है। यह या तो अनुक्रमिक होने की जरूरत नहीं है। मान, यदि वे स्पष्ट रूप से सेट हैं, तो कुछ अर्थ अर्थ या व्यावहारिक विचार को प्रतिबिंबित करने की आवश्यकता है। उदाहरण के लिए, enum"दीवार पर बोतलें" की संख्या 1 से 99 तक होनी चाहिए, जबकि enum4 की शक्तियों के लिए संभवतः 4 से शुरू होना चाहिए और 16, 64, 256 आदि के साथ जारी रहना चाहिए।

इसके अलावा, शून्य-मूल्यवान तत्व को enumकेवल तभी जोड़ा जाना चाहिए जब यह एक वैध स्थिति का प्रतिनिधित्व करता है। कभी-कभी "कोई नहीं," "अज्ञात," "लापता" आदि मान्य मूल्य हैं, लेकिन कई बार वे नहीं होते हैं।


-1

मैं 0 पर अपनी एनम शुरू करना पसंद करता हूं, क्योंकि यह डिफ़ॉल्ट है, लेकिन मुझे -1 के मान के साथ एक अज्ञात मूल्य भी शामिल करना पसंद है। यह तब डिफ़ॉल्ट बन जाता है और कभी-कभी डिबगिंग में मदद कर सकता है।


4
भयानक विचार। मान प्रकार के रूप में, एनम को हमेशा शून्य पर आरंभीकृत किया जाता है। यदि आप कुछ मान रखने वाले हैं, जो अज्ञात या असिंचित का प्रतिनिधित्व करता है, तो इसे 0. होना चाहिए। आप डिफ़ॉल्ट को -1 में नहीं बदल सकते हैं, शून्य-भरना पूरे सीएलआर में हार्ड-कोडित है।
बेन वोइगट

आह, मुझे यह एहसास नहीं था। जब मैं डीक्लियर / इनिशियलाइज़ करता हूं, तो मैं आम तौर पर एनम वैल्यू / प्रॉपर्टी का मूल्य निर्धारित करता हूं। सूचक के लिए धन्यवाद।
टॉमस मैकगिनेंस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.