2008-08-17 17 views
51

मान्य करें मुझे यह जानने के लिए एक पूर्णांक को सत्यापित करने की आवश्यकता है कि वैध एनम मान है या नहीं।एनम वैल्यूज

सी # में ऐसा करने का सबसे अच्छा तरीका क्या है?

+1

झंडे के साथ एक दृष्टिकोण यह डुप्लिकेट सवाल पर यह जवाब चेकआउट करने के लिए उपयोगी हो सकता है के लिए: http://stackoverflow.com/a/23177585/5190842 – Erik

+0

चेक 'EnumDataTypeAttribute' – Timeless

उत्तर

61

आप इन लोक जो मान डेटा न केवल हमेशा एक यूआई से आता है कि प्यार करने के लिए मिल गया है, लेकिन आपके नियंत्रण में एक यूआई!

IsDefined सबसे परिदृश्यों के लिए ठीक है, आप शुरू कर सकता है के साथ:

public static bool TryParseEnum<TEnum>(this int enumValue, out TEnum retVal) 
{ 
retVal = default(TEnum); 
bool success = Enum.IsDefined(typeof(TEnum), enumValue); 
if (success) 
{ 
    retVal = (TEnum)Enum.ToObject(typeof(TEnum), enumValue); 
} 
return success; 
} 

(जाहिर है सिर्फ ड्रॉप 'इस' यदि आप इसे एक उपयुक्त पूर्णांक विस्तार है नहीं लगता है)

+4

कृपया यह भी ध्यान दें कि Enum.IsDefined प्रतिबिंब का उपयोग करता है जो प्रदर्शन समस्याओं का कारण बन सकता है – Guldan

+0

यह पहले से ही अन्य उत्तरों में नोट किया गया है और संबोधित किया गया है। – Vman

9

ब्रैड अब्राम विशेष रूप से Enum.IsDefined के खिलाफ The Danger of Oversimplification पर चेतावनी देता है।

इस आवश्यकता से छुटकारा पाने का सबसे अच्छा तरीका (यानी, enums को सत्यापित करने की आवश्यकता) उन तरीकों को हटाना है जहां उपयोगकर्ता इसे गलत कर सकते हैं, उदाहरण के लिए, किसी प्रकार का इनपुट बॉक्स। ड्रॉप डाउन के साथ enums का उपयोग करें, उदाहरण के लिए, केवल वैध enums लागू करने के लिए।

+5

मेरी इनपुट एक XML फ़ाइल से आता है कई संभावित कार्यक्रमों में से एक द्वारा उत्पादित किया गया है कि मैं नियंत्रित नहीं करता कि डेटा की गुणवत्ता में काफी भिन्नता है। Enum.Is वास्तव में बुरा है परिभाषित है क्योंकि यह इस स्थिति में मेरे लिए सबसे अच्छा लगता है? –

+0

@ रिचर्ड जीवन में किसी भी चीज़ के साथ, ऐसे विशिष्ट मामले हैं जिनमें आम तौर पर एक बुरा विचार क्या होता है, उस स्थिति के लिए उपयुक्त समाधान होगा। अगर आपको लगता है कि यह आपके मामले के लिए सबसे अच्छा समाधान है, तो आगे बढ़ें। :) यहां तक ​​कि सिंगलटन और ग्लोबल वैरिएबल और नेस्टेड आईएफएस कुछ स्थितियों के लिए एक अच्छा विचार है ... –

+6

आपका दृष्टिकोण (यूआई में जो उपलब्ध है उसे सीमित करना) में समानता है जैसे 'एनम। आईएस डिफिफाइड': यदि यूआई कोड सिंक से बाहर है enum के साथ, तो आप बाहर की रेंज मान प्राप्त कर सकते हैं (यानी enum में घोषित नहीं)। हालांकि किसी को अभी भी इन मानों को संभालने की आवश्यकता है (जैसे 'स्विच' कथन में 'डिफ़ॉल्ट' केस होना), किसी ऑब्जेक्ट के फ़ील्ड में मान संग्रहीत करने से पहले 'Enum.IsDefined' का उपयोग करने के लिए यह एक अच्छा अभ्यास प्रतीत होता है: यह त्रुटि को होने की अनुमति देता है जल्दी पकड़ा, इसे तब तक तैरने की बजाय जब यह स्पष्ट नहीं है कि बोगस मूल्य कहाँ से आया था। –

1

मुझे यह link मिला जो इसे काफी अच्छी तरह से उत्तर देता है। यह का उपयोग करता है:

(ENUMTYPE)Enum.ToObject(typeof(ENUMTYPE), INT) 
+0

क्या यह एक अपवाद फेंक देगा यदि गैर-एनम पूर्णांक इसे पास किया गया हो? –

+3

@ रिचर्ड - हाँ यह ...3 साल बाद मैंने यह लिखा और स्वर्ग मेरी मदद करता है अगर मुझे पता है कि मैं क्या सोच रहा था - अगर यह फेंकता है तो –

+0

अपवाद को फेंकने से प्रदर्शन में कमी भी होती है। बेहतर समाधान होने पर आपको कभी अपवाद नहीं फेंकना चाहिए। – Kody

16

IMHO पोस्ट उत्तर के रूप में चिह्नित गलत है।
पैरामीटर और डेटा सत्यापन उन चीजों में से एक है जो दशकों पहले मुझे ड्रिल किया गया था।

क्यों क्योंकि अनिवार्य रूप से किसी भी पूर्णांक मान कोई त्रुटि फेंक बिना एक enum को सौंपा जा सकता

सत्यापन की आवश्यकता है।
मैंने कई दिनों सी # एनम प्रमाणीकरण का शोध किया क्योंकि यह कई मामलों में एक आवश्यक कार्य है।

कहां

मेरे लिए enum सत्यापन में मुख्य उद्देश्य एक फ़ाइल से पढ़ने डेटा को सत्यापित करने में है: आप कभी पता नहीं फ़ाइल दूषित करता है, तो किया गया है, या बाहर से संशोधित किया गया था, या उद्देश्य पर काट दिया गया था।
और क्लिपबोर्ड से चिपकाए गए एप्लिकेशन डेटा की enum सत्यापन के साथ: आप कभी नहीं जानते कि उपयोगकर्ता ने क्लिपबोर्ड सामग्री संपादित की है या नहीं।

उस ने कहा, मैंने कई तरीकों का शोध और परीक्षण करने में कई दिन व्यतीत किए हैं जिनमें मुझे ढूंढने या डिजाइन करने के हर तरीके के प्रदर्शन को प्रोफाइल करना शामिल है।

सिस्टम में कुछ भी कॉल करना। ईनम इतनी धीमी है कि यह उन कार्यों पर एक उल्लेखनीय प्रदर्शन दंड था जिसमें सैकड़ों या हजारों ऑब्जेक्ट्स थे जिनके गुणों में एक या अधिक enums थे जिन्हें सीमाओं के लिए मान्य किया जाना था।

नीचे की रेखा, सिस्टम में सब कुछ से दूर रहें। Enum वर्ग enum मानों को सत्यापित करते समय, यह डरावना धीमा है।

परिणाम

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

मैं एक या दो स्थिरांक कि ऊपरी और (वैकल्पिक) कम enum की सीमा से कर रहे हैं परिभाषित करते हैं, और उन्हें अगर() बयान के सत्यापन के लिए की एक जोड़ी में इस्तेमाल करते हैं।
एक नकारात्मक बात यह है कि यदि आप enum बदलते हैं तो आपको स्थिरांक को अपडेट करना सुनिश्चित करना होगा।
इस विधि भी तभी काम करता है enum एक "स्वचालित" शैली जहां प्रत्येक enum तत्व 0,1,2,3,4 के रूप में एक वृद्धिशील पूर्णांक मान जैसे .... यह झंडे या के साथ ठीक से काम नहीं करेगा है enums जिनके मूल्य वृद्धिशील नहीं हैं।

यह भी ध्यान रखें कि यह विधि नियमित रूप से तेज़ी से तेज है यदि नियमित int32s पर "<" ">" (जिसने मेरे परीक्षणों पर 38,000 टिक बनाए हैं)।

उदाहरण के लिए:

public const MyEnum MYENUM_MINIMUM = MyEnum.One; 
public const MyEnum MYENUM_MAXIMUM = MyEnum.Four; 

public enum MyEnum 
{ 
    One, 
    Two, 
    Three, 
    Four 
}; 

public static MyEnum Validate(MyEnum value) 
{ 
    if (value < MYENUM_MINIMUM) { return MYENUM_MINIMUM; } 
    if (value > MYENUM_MAXIMUM) { return MYENUM_MAXIMUM; } 
    return value; 
} 

निष्पादन

जो लोग रुचि रखते हैं के लिए, मैं एक enum सत्यापन पर निम्नलिखित रूपों प्रोफाइल, और यहाँ के परिणाम हैं।

रूपरेखा एक यादृच्छिक पूर्णांक इनपुट मूल्य के साथ प्रत्येक विधि पर एक लाख बार के एक पाश में रिलीज संकलन पर प्रदर्शन किया था। प्रत्येक परीक्षण 10 गुना से अधिक और औसत से चला गया था। टिक परिणामों में निष्पादित करने के लिए कुल समय शामिल होता है जिसमें यादृच्छिक संख्या पीढ़ी आदि शामिल होगी लेकिन वे परीक्षणों में निरंतर रहेंगे। 1 टिक = 10ns।

ध्यान दें कि कोड यहाँ पूरा परीक्षण कोड नहीं है, यह केवल बुनियादी enum सत्यापन विधि है। इन पर परीक्षण किए गए बहुत से अतिरिक्त बदलाव भी थे, और उन सभी के परिणामों के साथ यहां दिखाए गए उदाहरण के साथ 1,800,000 टिके हुए थे।

गोल परिणाम, उम्मीद है कि टाइप की कोई गलती के साथ सबसे तेजी से करने के लिए सूचीबद्ध धीमी।

सीमा विधि = 13,600,000 में निर्धारित टिक्स

public static T Clamp<T>(T value) 
{ 
    int minimum = Enum.GetValues(typeof(T)).GetLowerBound(0); 
    int maximum = Enum.GetValues(typeof(T)).GetUpperBound(0); 

    if (Convert.ToInt32(value) < minimum) { return (T)Enum.ToObject(typeof(T), minimum); } 
    if (Convert.ToInt32(value) > maximum) { return (T)Enum.ToObject(typeof(T), maximum); } 
    return value; 
} 

Enum.IsDefined = 1,800,000 टिक्स
नोट: इस कोड संस्करण न्यूनतम/अधिकतम लेकिन रिटर्न डिफ़ॉल्ट क्लैंप नहीं है सीमा से बाहर है, तो ।

public static T ValidateItem<T>(T eEnumItem) 
{ 
    if (Enum.IsDefined(typeof(T), eEnumItem) == true) 
     return eEnumItem; 
    else 
     return default(T); 
} 

System.Enum डाले साथ कन्वर्ट Int32 = 1,800,000 टिक

public static Enum Clamp(this Enum value, Enum minimum, Enum maximum) 
{ 
    if (Convert.ToInt32(value) < Convert.ToInt32(minimum)) { return minimum; } 
    if (Convert.ToInt32(value) > Convert.ToInt32(maximum)) { return maximum; } 
    return value; 
} 

अगर() न्यूनतम/अधिकतम स्थिरांक = 43,000 टिक = 42x और 316x द्वारा विजेता तेजी से।

public static MyEnum Clamp(MyEnum value) 
{ 
    if (value < MYENUM_MINIMUM) { return MYENUM_MINIMUM; } 
    if (value > MYENUM_MAXIMUM) { return MYENUM_MAXIMUM; } 
    return value; 
} 

-eol-

+6

हमारे enums की एक बड़ी संख्या संगत नहीं हैं इसलिए कई परिदृश्यों में एक विकल्प नहीं है। 'Enum.IsDefined (टाइपोफ (टी)' आपके परीक्षण परिदृश्य में धीमा हो जाएगा क्योंकि नेट बहुत प्रतिबिंब, मुक्केबाजी इत्यादि कर रहा है। हर बार जब आप अपनी आयात फ़ाइल में एक पंक्ति का विश्लेषण करते हैं तो इसे कॉल करना कभी तेज़ नहीं होगा। प्रदर्शन महत्वपूर्ण है तो मैं आयात की शुरुआत में एक बार Enum.GetValues ​​को कॉल करना चाहता हूं। यह कभी भी उतना तेज़ नहीं होगा <> तुलना करें लेकिन आप जानते हैं कि यह सभी enums के लिए काम करेगा। वैकल्पिक रूप से आप एक और बुद्धिमान enum पार्सर हो सकता है , मैं एक और जवाब पोस्ट करूंगा क्योंकि अच्छी तरह से प्रतिक्रिया देने की जगह नहीं है! – Vman

+0

क्या होगा यदि आपकी गणना मूल्यों को छोड़ देती है? –

+0

@ जॉनी 5 - उपर्युक्त जानकारी से: यह विधि केवल तभी काम करती है जब enum एक "auto" शैली है जहां प्रत्येक enum तत्व एक वृद्धिशील पूर्णांक मान होता है जैसे कि 0,1,2,3,4, .... यह ध्वज या enums के साथ ठीक से काम नहीं करेगा जिनके मूल्य वृद्धिशील नहीं हैं। – deegee

2

यह मैं इसे कैसे कई पदों के आधार पर काम ऑनलाइन करते हैं। ऐसा करने का कारण यह सुनिश्चित करना है कि Flags विशेषता के साथ चिह्नित enums भी सफलतापूर्वक सत्यापित किया जा सकता है।

public static TEnum ParseEnum<TEnum>(string valueString, string parameterName = null) 
{ 
    var parsed = (TEnum)Enum.Parse(typeof(TEnum), valueString, true); 
    decimal d; 
    if (!decimal.TryParse(parsed.ToString(), out d)) 
    { 
     return parsed; 
    } 

    if (!string.IsNullOrEmpty(parameterName)) 
    { 
     throw new ArgumentException(string.Format("Bad parameter value. Name: {0}, value: {1}", parameterName, valueString), parameterName); 
    } 
    else 
    { 
     throw new ArgumentException("Bad value. Value: " + valueString); 
    } 
} 
5

इस उत्तर deegee करने के जवाब देने के जो System.Enum के प्रदर्शन मुद्दों को उठाती है तो नहीं और अधिक तंग प्रदर्शन परिदृश्यों में enum सत्यापन संबोधित मेरे पसंदीदा जेनेरिक जवाब के रूप में लिया जाना चाहिए जवाब में है।

यदि आपके पास एक महत्वपूर्ण महत्वपूर्ण समस्या है जहां धीमी लेकिन कार्यात्मक कोड एक तंग लूप में चल रहा है तो मैं व्यक्तिगत रूप से कार्यक्षमता को कम करके हल करने के बजाय उस कोड को लूप से बाहर ले जाने पर विचार करता हूं। कोड को सीमित करने के लिए केवल संगत enums का समर्थन करने के लिए एक बग खोजने के लिए एक दुःस्वप्न हो सकता है, उदाहरण के लिए, भविष्य में कोई भी कुछ enum मूल्यों को कम करने का फैसला करता है। सरलता से आप केवल एक बार, सभी प्रतिबिंब, आदि को हजारों बार ट्रिगर करने से बचने के लिए शुरुआत में, Enum.GetValues ​​को कॉल कर सकते हैं। इससे आपको तत्काल प्रदर्शन में वृद्धि मिलनी चाहिए। आप और अधिक प्रदर्शन की जरूरत है और आप जानते हैं कि आपके enums का एक बहुत सन्निहित हैं (लेकिन आप अभी भी 'अपूर्ण' enums समर्थन करना चाहते हैं) आप एक मंच आगे जाकर की तरह कुछ कर सकता है:

public abstract class EnumValidator<TEnum> where TEnum : struct, IConvertible 
{ 
    protected static bool IsContiguous 
    { 
     get 
     { 
      int[] enumVals = Enum.GetValues(typeof(TEnum)).Cast<int>().ToArray(); 

      int lowest = enumVals.OrderBy(i => i).First(); 
      int highest = enumVals.OrderByDescending(i => i).First(); 

      return !Enumerable.Range(lowest, highest).Except(enumVals).Any(); 
     } 
    } 

    public static EnumValidator<TEnum> Create() 
    { 
     if (!typeof(TEnum).IsEnum) 
     { 
      throw new ArgumentException("Please use an enum!"); 
     } 

     return IsContiguous ? (EnumValidator<TEnum>)new ContiguousEnumValidator<TEnum>() : new JumbledEnumValidator<TEnum>(); 
    } 

    public abstract bool IsValid(int value); 
} 

public class JumbledEnumValidator<TEnum> : EnumValidator<TEnum> where TEnum : struct, IConvertible 
{ 
    private readonly int[] _values; 

    public JumbledEnumValidator() 
    { 
     _values = Enum.GetValues(typeof (TEnum)).Cast<int>().ToArray(); 
    } 

    public override bool IsValid(int value) 
    { 
     return _values.Contains(value); 
    } 
} 

public class ContiguousEnumValidator<TEnum> : EnumValidator<TEnum> where TEnum : struct, IConvertible 
{ 
    private readonly int _highest; 
    private readonly int _lowest; 

    public ContiguousEnumValidator() 
    { 
     List<int> enumVals = Enum.GetValues(typeof (TEnum)).Cast<int>().ToList(); 

     _lowest = enumVals.OrderBy(i => i).First(); 
     _highest = enumVals.OrderByDescending(i => i).First(); 
    } 

    public override bool IsValid(int value) 
    { 
     return value >= _lowest && value <= _highest; 
    } 
} 

कहाँ अपने पाश हो जाता है कुछ की तरह:

//Pre import-loop 
EnumValidator<MyEnum> enumValidator = EnumValidator<MyEnum>.Create(); 
while(import) //Tight RT loop. 
{ 
    bool isValid = enumValidator.IsValid(theValue); 
} 

मुझे यकीन है कि EnumValidator वर्गों और अधिक कुशलता से (यह प्रदर्शित करने के लिए बस एक त्वरित हैक है) लिखा सकता हूँ लेकिन काफी स्पष्ट रूप से कौन परवाह करता है क्या आयात पाश के बाहर होता है? एकमात्र बिट जो सुपर-फास्ट होने की आवश्यकता है वह लूप के भीतर है। लूप में एक अनावश्यक अगर-enumContiguous- और अन्यथा से बचने के लिए अमूर्त वर्ग मार्ग लेने का यही कारण था (कारखाना अनिवार्य रूप से यह आगे करता है)। ब्रेवटी के लिए आप कुछ पाखंड को ध्यान में रखेंगे, यह कोड int-enums के लिए कार्यक्षमता को बाधित करता है। मुझे int का उपयोग करने के बजाय आईसीओवर्टिबल का उपयोग करना चाहिए लेकिन यह जवाब पहले से ही पर्याप्त शब्द है!

4

जैसा कि अन्य ने उल्लेख किया है, Enum.IsDefined धीमा है, कुछ ऐसा है जो आपको पता होना चाहिए कि यह लूप में है या नहीं।

एकाधिक तुलना करते समय, एक तेज विधि है कि पहले मान को HashSet में रखें। तब बस कि क्या मान मान्य है की जाँच करने के, तो जैसे Contains का उपयोग करें: यदि एक मूल्य के एक गणन में कोई मान्य मान है

int userInput = 4; 
// below, Enum.GetValues converts enum to array. We then convert the array to hashset. 
HashSet<int> validVals = new HashSet<int>((int[])Enum.GetValues(typeof(MyEnum))); 
// the following could be in a loop, or do multiple comparisons, etc. 
if (validVals.Contains(userInput)) 
{ 
    // is valid 
} 
+0

इस उत्तर पर एक और लेना होगा 'हैशसेट ' जो 'int' पर डालने की आवश्यकता को हटा देगा यदि आप 'int' के बजाय 'enum' को मान्य कर रहे हैं। इसे सेट करने के लिए कोड इस तरह दिखेगा: 'var validVals = new हैशसेट (Enum.GetValues ​​(typeof (MyEnum))। ()) कास्ट करें;'। उपयोग निश्चित रूप से वही होगा। – Erik

0

प्रमाणित करने के लिए, आप केवल स्थिर विधि Enum.IsDefined कॉल करने के लिए की जरूरत है।

int value = 99;//Your int value 
if (Enum.IsDefined(typeof(your_enum_type), value)) 
{ 
    //Todo when value is valid 
}else{ 
    //Todo when value is not valid 
} 
+0

गलत होने के लिए डाउनवॉटेड नहीं है, लेकिन 8 साल के अंत में एक उत्तर लिखने के लिए जो कोई नई जानकारी प्रदान नहीं करता है जो स्वीकार्य उत्तर में पहले से नहीं है। –