अवैध ईनम मूल्य के लिए कास्टिंग कास्टिंग अपवाद क्यों नहीं है?


124

अगर मेरे पास कोई एनम है तो:

enum Beer
{
    Bud = 10,
    Stella = 20,
    Unknown
}

जब यह intइन मानों को एक प्रकार के बाहर रखता है तो यह अपवाद क्यों नहीं फेंकता है Beer?

उदाहरण के लिए निम्नलिखित कोड एक अपवाद नहीं फेंकता है, यह कंसोल को '50' आउटपुट देता है:

int i = 50;
var b = (Beer) i;

Console.WriteLine(b.ToString());

मुझे यह अजीब लगता है ... क्या कोई स्पष्ट कर सकता है?


27
ध्यान दें कि आप हमेशा जांच सकते हैं कि क्या मान Enum.IsDefined के साथ मान्य है ।
टिम श्मेल्टर

शांत मुझे पता नहीं था कि, शायद मैं जिस समस्या को हल करने की कोशिश कर रहा हूँ, उसमें इसका इस्तेमाल
करूंगा

4
लेकिन यह भी पढ़े: सुनहरीमछली।
blogspot.com/2008/03/…

1
स्टैला को बड के रूप में दो बार लायक बनाने के लिए तैयार किया गया।
दान बेखर

जवाबों:


81

एक Enum पार्स करने के साथ भ्रम से लिया गया

यह .NET बनाने वाले लोगों की ओर से एक निर्णय था। एक enum एक और मान प्रकार (के द्वारा समर्थित है int, short, byte, आदि), और इसलिए यह वास्तव में है कि उन मूल्य प्रकार के लिए मान्य है किसी भी मूल्य हो सकता है।

मैं व्यक्तिगत रूप से इस काम के तरीके का प्रशंसक नहीं हूं, इसलिए मैंने उपयोगिता विधियों की एक श्रृंखला बनाई:

/// <summary>
/// Utility methods for enum values. This static type will fail to initialize 
/// (throwing a <see cref="TypeInitializationException"/>) if
/// you try to provide a value that is not an enum.
/// </summary>
/// <typeparam name="T">An enum type. </typeparam>
public static class EnumUtil<T>
    where T : struct, IConvertible // Try to get as much of a static check as we can.
{
    // The .NET framework doesn't provide a compile-checked
    // way to ensure that a type is an enum, so we have to check when the type
    // is statically invoked.
    static EnumUtil()
    {
        // Throw Exception on static initialization if the given type isn't an enum.
        Require.That(typeof (T).IsEnum, () => typeof(T).FullName + " is not an enum type.");
    }

    /// <summary>
    /// In the .NET Framework, objects can be cast to enum values which are not
    /// defined for their type. This method provides a simple fail-fast check
    /// that the enum value is defined, and creates a cast at the same time.
    /// Cast the given value as the given enum type.
    /// Throw an exception if the value is not defined for the given enum type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="enumValue"></param>
    /// <exception cref="InvalidCastException">
    /// If the given value is not a defined value of the enum type.
    /// </exception>
    /// <returns></returns>
    public static T DefinedCast(object enumValue)

    {
        if (!System.Enum.IsDefined(typeof(T), enumValue))
            throw new InvalidCastException(enumValue + " is not a defined value for enum type " +
                                           typeof (T).FullName);
        return (T) enumValue;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="enumValue"></param>
    /// <returns></returns>
    public static T Parse(string enumValue)
    {
        var parsedValue = (T)System.Enum.Parse(typeof (T), enumValue);
        //Require that the parsed value is defined
        Require.That(parsedValue.IsDefined(), 
            () => new ArgumentException(string.Format("{0} is not a defined value for enum type {1}", 
                enumValue, typeof(T).FullName)));
        return parsedValue;
    }

    public static bool IsDefined(T enumValue)
    {
        return System.Enum.IsDefined(typeof (T), enumValue);
    }

}


public static class EnumExtensions
{
    public static bool IsDefined<T>(this T enumValue)
        where T : struct, IConvertible
    {
        return EnumUtil<T>.IsDefined(enumValue);
    }
}

इस तरह, मैं कह सकता हूँ:

if(!sEnum.IsDefined()) throw new Exception(...);

... या:

EnumUtil<Stooge>.Parse(s); // throws an exception if s is not a defined value.

संपादित करें

ऊपर दिए गए स्पष्टीकरण से परे, आपको यह महसूस करना होगा कि Enum का .NET संस्करण जावा-प्रेरित एक से अधिक सी-प्रेरित पैटर्न का अनुसरण करता है। इससे "बिट फ्लैग" इनमों का होना संभव है, जो यह निर्धारित करने के लिए बाइनरी पैटर्न का उपयोग कर सकता है कि क्या कोई विशेष "ध्वज" एनाम मान में सक्रिय है। आप झंडे के हर संभव संयोजन को परिभाषित करने के लिए किया था, तो (यानी MondayAndTuesday, MondayAndWednesdayAndThursday), इन अत्यंत कठिन होगा। तो अपरिभाषित Enum मानों का उपयोग करने की क्षमता होना वास्तव में आसान हो सकता है। जब आप इन प्रकार की चालों का लाभ नहीं उठाते हैं, तो बस आपको थोड़े अतिरिक्त काम की आवश्यकता होती है।


अच्छा ... मैं इस तरह से या तो काम करने का प्रशंसक नहीं हूं, जो मेरे लिए विचित्र लगता है
jcvandan

3
@ डॉर्मिशर: "'तीस पागलपन, फिर भी विधि नहीं है।" मेरा संपादन देखें।
स्ट्रिपिंगवर्यर

2
@StriplingWarrior, ब्याज के लिए। जावा समतुल्य EnumSet.of (सोमवार, बुधवार, गुरुवार) है। EnumSet के अंदर सिर्फ एक लंबा है। तो बहुत दक्षता नुकसान के बिना एक अच्छा एपीआई देता है।
इयान

2
"आवश्यकता है। ()" => stackoverflow.com/questions/4892548/…
जॉन

@StriplingWarrior अपने पार्स तरीके से आप एक एक्सटेंशन विधि की तरह IsDefined कॉल करने की कोशिश कर रहे हैं। हालाँकि, आप जिस तरह से बाधाओं के साथ EnumUtil वर्ग (Enum के लिए स्थिर जाँच करने के लिए, जो मुझे बहुत पसंद है) बनाने के लिए प्रयास करने के कारण IsDefined विधि को एक्सटेंशन विधि नहीं बनाया जा सकता है। हालांकि यह प्रभाव में है कि मुझे एक सामान्य वर्ग पर एक विस्तार विधि नहीं बना सकता है। कोई विचार?
CJC

55

Enums अक्सर झंडे के रूप में उपयोग किया जाता है:

[Flags]
enum Permission
{
    None = 0x00,
    Read = 0x01,
    Write = 0x02,
}
...

Permission p = Permission.Read | Permission.Write;

पी का मान पूर्णांक 3 है, जो एनम का मान नहीं है, लेकिन स्पष्ट रूप से एक वैध मूल्य है।

मैंने व्यक्तिगत रूप से एक अलग समाधान देखा होगा; मैं इसके बजाय "बिट एरे" पूर्णांक प्रकार और "अलग मूल्य का एक प्रकार" बनाने की क्षमता रखता था, क्योंकि इन दोनों को "एनम" में बदलने के बजाय दो अलग-अलग भाषा विशेषताएँ होती हैं। लेकिन यह वही है जो मूल भाषा और रूपरेखा डिजाइनर के साथ आया था; परिणामस्वरूप, हमें एनम के गैर-घोषित मूल्यों को कानूनी मान देने की अनुमति देनी होगी।


19
लेकिन 3 "स्पष्ट रूप से एक वैध मूल्य है" ओपी के बिंदु को मजबूत करता है। यह [झंडे] विशेषता कंपाइलर को परिभाषित एनम या वैध मूल्य की तलाश करने के लिए कह सकती है। मैं तो बस कह रहा हूं'।
लार्सटेक

15

संक्षिप्त उत्तर: भाषा डिजाइनरों ने भाषा को इस तरह से डिजाइन करने का निर्णय लिया।

Section 6.2.2: Explicit enumeration conversionsC # भाषा विशिष्टता का लंबा उत्तर कहता है:

दो प्रकार के बीच एक स्पष्ट गणना रूपांतरण किसी भी सहभागी एनुम-प्रकार को उस एन-टाइप के अंतर्निहित प्रकार के रूप में माना जाता है, और फिर परिणामी प्रकारों के बीच एक अंतर्निहित या स्पष्ट संख्यात्मक रूपांतरण का प्रदर्शन किया जाता है। उदाहरण के लिए, एक एनुम-टाइप ई के साथ और अंतर्निहित प्रकार के इंट को देखते हुए, ई से बाइट में रूपांतरण को स्पष्ट संख्यात्मक रूपांतरण (numeric6.2.1) से इंट से बाइट तक संसाधित किया जाता है, और बाइट से ई में रूपांतरण को संसाधित किया जाता है। एक अंतर्निहित संख्यात्मक रूपांतरण (.16.1.2) बाइट से इंट तक।

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

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


क्या आपको यह अजीब लगता है? मुझे लगा कि एक एनम का मुख्य बिंदु सुरक्षित रूप से पूर्णांकों की एक श्रृंखला को समूह बनाना है जिसे हम अलग-अलग अर्थ भी बता सकते हैं। मेरे लिए किसी भी पूर्णांक मान को पराजित करने के लिए एक एनुम प्रकार की अनुमति देना यह उद्देश्य है।
jcvandan

@ डॉर्मिशर: मैंने अभी-अभी एडिट किया और अंत में थोड़ा जोड़ा। आप के बाद "सुरक्षा" प्रदान करने में एक लागत शामिल है। कहा जा रहा है, सामान्य उपयोग के साथ , यह वास्तव में एक समस्या नहीं है।
रीड कोपसे

9

से प्रलेखन :

प्रकार के दिनों के एक चर को अंतर्निहित प्रकार की सीमा में किसी भी मूल्य को सौंपा जा सकता है; मान नामांकित स्थिरांक तक सीमित नहीं हैं।

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