System.Enum से आधार पूर्णांक में कैसे बदलें?


93

मैं किसी भी System को परिवर्तित करने के लिए एक जेनेरिक विधि बनाना चाहता हूं। किसी भी प्रकार के इसके पूर्णांक मान के लिए व्युत्पन्न प्रकार, बिना किसी स्ट्रिंग के पार्सिंग के बिना और अधिमानतः।

जैसे, मुझे क्या चाहिए कुछ इस तरह है:

// Trivial example, not actually what I'm doing.
class Converter
{
    int ToInteger(System.Enum anEnum)
    {
        (int)anEnum;
    }
}

लेकिन यह काम नहीं करता है। रेस्परर रिपोर्ट करता है कि आप 'int. टाइप' करने के लिए 'System.Enum' टाइप की अभिव्यक्ति नहीं कर सकते हैं।

अब मैं इस समाधान के साथ आया हूं, लेकिन मेरे पास कुछ अधिक कुशल है।

class Converter
{
    int ToInteger(System.Enum anEnum)
    {
        return int.Parse(anEnum.ToString("d"));
    }
}

कोई सुझाव?


1
मेरा मानना ​​है कि यह कंपाइलर है जो शिकायत कर रहा है, न कि रेस्पर।
कुगेल

1
जरुरी नहीं। मेरे पास System.Enum पर एक विस्तार विधि है, और कभी-कभी Resharper शिकायत करने का फैसला करता है: उदाहरण तर्क तर्क 'Some.Cool.Type.That.Is.An.Enum' को 'System.Enum' में तब परिवर्तित नहीं कर सकता जब निर्विवाद रूप से एक एनम हो। अगर मैं कोड संकलित करता हूं और चलाता हूं तो यह ठीक काम करता है। अगर मैं वी.एस. को बंद कर देता हूं, तो रेस्पर कैश को उड़ा दें, और इसे वापस आग दें, एक बार इसकी मरम्मत के बाद सब कुछ ठीक हो जाता है। मेरे लिए यह किसी प्रकार का कैश स्नैफू है। उसके लिए समान हो सकता है।
मीर

@ मीर मैं इस पर भी "शिकायत" कर चुका हूँ। मेरे लिए एक ही तय है। निश्चित नहीं है कि यह इन प्रकारों को मिश्रित क्यों करता है, लेकिन यह निश्चित रूप से संकलक नहीं है।
akousmata

जवाबों:


134

यदि आप कास्ट नहीं करना चाहते हैं,

Convert.ToInt32()

कर सकता था।

डायरेक्ट कास्ट (के माध्यम से (int)enumValue) संभव नहीं है। ध्यान दें कि यह भी हो सकता है "खतरनाक" के बाद से एक enum अलग अंतर्निहित प्रकार हो सकता है ( int, long, byte...)।

औपचारिक रूप से: दोनों के System.Enumसाथ कोई सीधा संबंध नहीं है Int32(हालांकि दोनों ही ValueTypeएस), इसलिए स्पष्ट कास्ट प्रकार प्रणाली के भीतर सही नहीं हो सकता


2
Converter.ToInteger(MyEnum.MyEnumConstant);आपको यहाँ कोई त्रुटि नहीं देगा। कृपया वह हिस्सा संपादित करें।
नवाफाल

धन्यवाद, @nawfal, आप सही हैं। मैंने प्रतिक्रिया को संपादित किया (और कुछ नया सीखा :) :))
मार्टिनस्टनर

काम नहीं कर रहा है यदि अंतर्निहित प्रकार अलग हैint
एलेक्स

@YaroslavSivakov यह काम नहीं करेगा उदाहरण के लिए longenum।
एलेक्स ज़ुकोवस्की

System.Enumएक वर्ग है, इसलिए यह एक संदर्भ प्रकार है। मान शायद बॉक्सिंग हैं।
तीजय

42

मुझे यह एक वस्तु से कास्टिंग और फिर एक इंट में काम करने के लिए मिला:

public static class EnumExtensions
{
    public static int ToInt(this Enum enumValue)
    {
        return (int)((object)enumValue);
    }
}

यह बदसूरत है और शायद सबसे अच्छा तरीका नहीं है। मैं इसके साथ खिलवाड़ करता रहूंगा, यह देखने के लिए कि क्या मैं कुछ बेहतर कर सकता हूं ...।

संपादित करें: बस ConvertToInt32 (enumValue) के रूप में अच्छी तरह से काम करता है कि पोस्ट करने के बारे में था, और देखा कि मार्टिनस्टेनर ने मुझे इसे हराया।

public static class EnumExtensions
{
    public static int ToInt(this Enum enumValue)
    {
        return Convert.ToInt32(enumValue);
    }
}

परीक्षा:

int x = DayOfWeek.Friday.ToInt();
Console.WriteLine(x); // results in 5 which is int value of Friday

EDIT 2: टिप्पणियों में, किसी ने कहा कि यह केवल C # 3.0 में काम करता है। मैंने वीएस 2005 में इस तरह परीक्षण किया और यह काम किया:

public static class Helpers
{
    public static int ToInt(Enum enumValue)
    {
        return Convert.ToInt32(enumValue);
    }
}

    static void Main(string[] args)
    {
        Console.WriteLine(Helpers.ToInt(DayOfWeek.Friday));
    }

मैंने आपको +1 दिया लेकिन यह समाधान केवल C # 3.0 और उच्चतर के साथ काम करने वाला है।
वादिम

मुझे लगता है, यह केवल संकलक को संतुष्ट करता है। क्या आपने इसे रनटाइम पर परीक्षण करने का प्रबंधन किया था? मैं इस समारोह के लिए कोई मूल्य नहीं दे सकता था ...
मार्टिनस्टेनेर

क्योंकि यह एक विस्तार विधि है? या C # के पुराने संस्करणों में enums के बारे में कुछ अलग है?
बीफ्री

मैंने अपनी पोस्ट के अंत में एक परीक्षण जोड़ा। मैंने कोशिश की और यह मेरे लिए काम किया।
बीफ्री

@BFree: यह केवल विस्तार विधियों के साथ काम करता है। मैंने इसे "पुराने-शैली" फ़ंक्शन (C # 2.0 में) के साथ आज़माया और वास्तव में इसके लिए किसी भी मान को पास करने के लिए वाक्यविन्यास को प्रबंधित करने का प्रबंधन नहीं किया (यही मेरी पिछली टिप्पणी के बारे में था)
मार्टिनस्टेनर

14

यदि आपको किसी भी एनम को इसके अंतर्निहित प्रकार में बदलने की आवश्यकता है (सभी एनम द्वारा समर्थित नहीं हैं int) तो आप उपयोग कर सकते हैं:

return System.Convert.ChangeType(
    enumValue,
    Enum.GetUnderlyingType(enumValue.GetType()));

5
यह एकमात्र बुलेटप्रूफ उत्तर है।
रुडी

क्या यह बॉक्सिंग अनबॉक्सिंग का कारण है?
b.ben

@ b.ben हाँ। पहले तर्क के लिए Convert.ChangeTypeस्वीकार करता objectहै, और लौटता है object
ड्रू नोकें जूल

हाँ, मैं वास्तव में इस पर @Rudey से सहमत हूं, किसी भी तरह आपको प्रदर्शन परीक्षण करना चाहिए। BFree का समाधान अब तक सबसे तेज है। लगभग आठ गुना तेज। वैसे भी हम अभी भी टिक्स के बारे में बात कर रहे हैं।
बीस

10

आपको एक सहायक विधि के साथ पहिया को सुदृढ़ करने की आवश्यकता क्यों है? enumअपने अंतर्निहित प्रकार के लिए एक मूल्य डालना पूरी तरह से कानूनी है ।

यह कम टाइपिंग है, और मेरी राय में अधिक पठनीय, उपयोग करने के लिए ...

int x = (int)DayOfWeek.Tuesday;

... बल्कि ऐसा कुछ ...

int y = Converter.ToInteger(DayOfWeek.Tuesday);
// or
int z = DayOfWeek.Tuesday.ToInteger();

6
मैं किसी भी एनम मान को परिवर्तित करना चाहता हूं। यानी, मेरे पास विभिन्न प्रकार के वर्ग हैं जिनके पास एनम फ़ील्ड्स हैं जो कुछ कोड द्वारा जेनेरिक तरीके से संसाधित किए जा रहे हैं। यही कारण है कि इंट करने के लिए एक साधारण कास्ट उचित नहीं है।
orj

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

2
कभी-कभी आप सीधे एनम नहीं डाल सकते हैं, जैसे कि सामान्य विधि के मामले में। चूँकि जेनेरिक विधियाँ दुश्मनी करने के लिए विवश नहीं हो सकती हैं, इसलिए आप इसे संरचना जैसी चीज़ के लिए विवश करते हैं, जिसे किसी इंट में नहीं डाला जा सकता है। उस स्थिति में, आप इसे करने के लिए Convert.ToInt32 (enum) का उपयोग कर सकते हैं।
डैनियल टी।

मुझे यह विचार पसंद आया कि एक्सटेंशन विधि Toteteger () ToString () के समान प्रारूप का अनुसरण करती है। मुझे लगता है कि जब आप इंट वैल्यू चाहते हैं तो एक तरफ इंट को कास्ट करना कम रीडेबल होता है और जब हम स्ट्रिंग वैल्यू की जरूरत होती है, खासकर तब जब कोड साइड में हो।
लुईस एगलटन

इसके अलावा, एक्सटेंशन विधि का उपयोग करने से आपके कोड आधार में स्थिरता जुड़ सकती है। चूंकि, @nawfal ने बताया, ऐसे कई तरीके हैं जिनसे आप एक एनम से अंतर मान प्राप्त कर सकते हैं, एक विस्तार विधि बना सकते हैं और इसके उपयोग को लागू करने का अर्थ है कि हर बार जब आप एक एनम का अंतर मान प्राप्त करते हैं तो आप उसी विधि का उपयोग कर रहे हैं
लुईस एगलटन

4

यहाँ मेरे जवाब से :

इसमें दिया eगया है:

Enum e = Question.Role;

फिर ये काम:

int i = Convert.ToInt32(e);
int i = (int)(object)e;
int i = (int)Enum.Parse(e.GetType(), e.ToString());
int i = (int)Enum.ToObject(e.GetType(), e);

अंतिम दो सादे बदसूरत हैं। पहला वाला अधिक पठनीय होना चाहिए, हालांकि दूसरा वाला ज्यादा तेज है। या हो सकता है एक विस्तार विधि दोनों दुनिया का सबसे अच्छा, सबसे अच्छा है।

public static int GetIntValue(this Enum e)
{
    return e.GetValue<int>();
}

public static T GetValue<T>(this Enum e) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
{
    return (T)(object)e;
}

अब आप कॉल कर सकते हैं:

e.GetValue<int>(); //or
e.GetIntValue();

क्या आप सुनिश्चित हैं कि दूसरा तेज है? मुझे लगता है कि यह Enum बॉक्स और फिर unbox वापस int करने के लिए होगा?
योयो

1
@yoyo eवैरिएबल में पहले से ही वास्तविक मूल्य प्रकार का बॉक्सिंग उदाहरण है, यानी, एनम। जब आप लिखते हैं तो Enum e = Question.Role;यह पहले से ही बॉक्सिंग है। प्रश्न बॉक्सिंग System.Enumको अंतर्निहित int प्रकार (अनबॉक्सिंग) में परिवर्तित करने के बारे में है । इसलिए यहां अनबॉक्सिंग केवल प्रदर्शन की चिंता है। (int)(object)eएक डायरेक्ट अनबॉक्स कॉल है; हाँ अन्य दृष्टिकोणों की तुलना में तेज़ होना चाहिए। यह देखें
nawfal

स्पष्टीकरण के लिए धन्यवाद। मैं गलत धारणा के तहत था कि System.Enum का एक उदाहरण एक अनबॉक्स मूल्य था। इसे भी देखें - msdn.microsoft.com/en-us/library/aa691158(v=vs.71).aspx
yoyo

@ योयो हम्म। लिंक से संबंधित उद्धरण: किसी भी एनुम-प्रकार से टाइप करें System.Enum।
नवफाल

1

एक से कास्टिंग System.Enumएक करने के लिए int(इस पर भी है मेरे लिए ठीक काम करता है MSDN )। शायद यह एक रिचार्पर बग है।


1
आप किस रनटाइम का उपयोग कर रहे हैं?
जोशबर्के

2
लिंक उप-प्रकारों की कास्टिंग दिखाता है System.Enum, System.Enumस्वयं नहीं ।
नवफाल

इसी तरह की एक समस्या मेरे पास एक Resharper cache snafu थी। VS को बंद करने और Resharper कैश को हटाने से त्रुटि पूरी तरह से गायब हो गई, यहां तक ​​कि पूर्ण rescan के बाद भी।
मीर

1

चूंकि एनम बाइट, सोबते, शॉर्ट, यूथोर्ट, इंट, यूइंट, लॉन्ग और अलॉन्ग तक सीमित हैं, इसलिए हम कुछ धारणाएं बना सकते हैं।

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

बेशक, आपको अभी भी यह तय करने की आवश्यकता है कि जब परिणाम एक इंट के अंदर फिट नहीं होता है तो क्या करें। मुझे लगता है कि कास्टिंग ठीक है, लेकिन अभी भी कुछ गोटे हैं:

  1. इंटम (लंबी और लंबी) की तुलना में बड़े क्षेत्र के साथ एक प्रकार के आधार पर एनमों के लिए, यह संभव है कि कुछ एनम समान मूल्य का मूल्यांकन करेंगे।
  2. यदि आप किसी चेक किए गए क्षेत्र में हैं तो int.MaxValue से बड़ा नंबर डालना एक अपवाद फेंक देगा।

यहाँ मेरा सुझाव है, मैं इसे इस समारोह में उजागर करने के लिए पाठक के पास छोड़ दूँगा; एक सहायक या एक विस्तार के रूप में।

public int ToInt(Enum e)
{
  unchecked
  {
    if (e.GetTypeCode() == TypeCode.UInt64)
      return (int)Convert.ToUInt64(e);
    else
      return (int)Convert.ToInt64(e);
  }
}

-1

यह मत भूलो कि Enum प्रकार में ही स्थैतिक सहायक कार्यों का एक समूह है। यदि आप सभी एनुम का एक उदाहरण अपने संबंधित पूर्णांक प्रकार में बदलना चाहते हैं, तो कास्टिंग संभवतः सबसे कुशल तरीका है।

मुझे लगता है कि ReSharper को शिकायत है क्योंकि Enum किसी विशेष प्रकार का एन्यूमरेशन नहीं है, और Enumerations खुद एक स्केलर वैल्यूएटाइप से निकलते हैं, एनम नहीं। यदि आपको एक सामान्य तरीके से अनुकूलनीय कास्टिंग की आवश्यकता है, तो मैं कहूंगा कि यह आपको अच्छी तरह से सूट कर सकता है (ध्यान दें कि गणना प्रकार स्वयं भी सामान्य में शामिल है:

public static EnumHelpers
{
    public static T Convert<T, E>(E enumValue)
    {
        return (T)enumValue;
    }
}

यह तो इस तरह इस्तेमाल किया जा सकता है:

public enum StopLight: int
{
    Red = 1,
    Yellow = 2,
    Green = 3
}

// ...

int myStoplightColor = EnumHelpers.Convert<int, StopLight>(StopLight.Red);

मैं अपने सिर के ऊपर से निश्चित रूप से नहीं कह सकता, लेकिन उपरोक्त कोड को C # के प्रकार के अनुमान से भी समर्थन मिल सकता है, जिससे निम्नलिखित की अनुमति मिलती है:

int myStoplightColor = EnumHelpers.Convert<int>(StopLight.Red);

1
दुर्भाग्य से, आपके उदाहरण में ई किसी भी प्रकार का हो सकता है। जेनरिक मुझे टाइप पैरामीटर बाधा के रूप में Enum का उपयोग करने की अनुमति नहीं देता है। मैं यह नहीं कह सकता: जहां T: Enum
वादिम

आप जहां T: संरचना का उपयोग कर सकते हैं, हालांकि। यह उतना सख्त नहीं है जितना आप चाहते हैं, लेकिन यह किसी भी संदर्भ प्रकार को काट देगा (जो मुझे लगता है कि आपका क्या करने की कोशिश कर रहा है।)
jrista

आप का उपयोग कर सकते हैं: अगर (टाइपोफ (ई)। आईसनेम) नए तर्क को फेंक देते हैं ("ई एक एनुमरेटेड टाइप होना चाहिए");
डायडियोरा

1
यह दूर से भी सही नहीं है, स्थैतिक सहायक भी मान्य नहीं है।
निकोली

1
EnumHelpers.Convert<int, StopLight>(StopLight.Red);इसके बजाय किसी का उपयोग क्यों करना चाहिए (int)StopLight.Read;? साथ ही सवाल यह भी है System.Enum
नवाफाल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.