मैं एक System.Type को उसके अशक्त संस्करण में कैसे परिवर्तित करूं?


79

एक बार फिर से उनमें से एक: "क्या मेरी सहायक विधि के बजाय चीजों को करने का एक आसान तरीका है?"

इसलिए एक अशक्त प्रकार से अंतर्निहित प्रकार प्राप्त करना आसान है, लेकिन मुझे .NET प्रकार का अशक्त संस्करण कैसे मिलेगा?

तो मेरे पास है

typeof(int)
typeof(DateTime)
System.Type t = something;

और मैं चाहता हूँ

int? 
DateTime?

या

Nullable<int> (which is the same)
if (t is primitive) then Nullable<T> else just T

क्या कोई अंतर्निहित विधि है?

जवाबों:


115

यहाँ मैं उपयोग कोड है:

Type GetNullableType(Type type) {
    // Use Nullable.GetUnderlyingType() to remove the Nullable<T> wrapper if type is already nullable.
    type = Nullable.GetUnderlyingType(type) ?? type; // avoid type becoming null
    if (type.IsValueType)
        return typeof(Nullable<>).MakeGenericType(type);
    else
        return type;
}

अच्छा लगा! यह वास्तव में साफ समाधान है।
— ljs

बहुत बढ़िया जवाब! मुझे इसकी ही खोज थी।
— एलेक्स डग्गलबी

10
ध्यान दें कि Nullable.GetUnderlyingType यदि अशक्त नहीं है, तो अशक्त देता है, इसलिए आपको इसके लिए जांच करनी होगी।
— अमित जी

1
@AmitG तुम सही हो। nullजब मैं इस फ़ंक्शन में वैल्यू टाइप पास करता हूं तो मुझे त्रुटि का सामना करना पड़ता है ।
— इलुमिनेटर

1
typeजैसा कि IsValueType@AmitG ने कहा, आपको वास्तव में यह सुनिश्चित करने की आवश्यकता है कि संपत्ति तक पहुंचने से पहले यह शून्य नहीं है । -1 जब तक यह तय नहीं हो जाता है
— मैट थॉमस

16

मेरे पास अपनी उपयोगिता पुस्तकालय में लिखी गई कुछ विधियाँ हैं, जिन पर मैंने बहुत भरोसा किया है। पहला वह तरीका है जो किसी भी प्रकार को उसके संबंधित Nullable <टाइप> फॉर्म में परिवर्तित करता है:

    /// <summary>
    /// [ <c>public static Type GetNullableType(Type TypeToConvert)</c> ]
    /// <para></para>
    /// Convert any Type to its Nullable&lt;T&gt; form, if possible
    /// </summary>
    /// <param name="TypeToConvert">The Type to convert</param>
    /// <returns>
    /// The Nullable&lt;T&gt; converted from the original type, the original type if it was already nullable, or null 
    /// if either <paramref name="TypeToConvert"/> could not be converted or if it was null.
    /// </returns>
    /// <remarks>
    /// To qualify to be converted to a nullable form, <paramref name="TypeToConvert"/> must contain a non-nullable value 
    /// type other than System.Void.  Otherwise, this method will return a null.
    /// </remarks>
    /// <seealso cref="Nullable&lt;T&gt;"/>
    public static Type GetNullableType(Type TypeToConvert)
    {
        // Abort if no type supplied
        if (TypeToConvert == null)
            return null;

        // If the given type is already nullable, just return it
        if (IsTypeNullable(TypeToConvert))
            return TypeToConvert;

        // If the type is a ValueType and is not System.Void, convert it to a Nullable<Type>
        if (TypeToConvert.IsValueType && TypeToConvert != typeof(void))
            return typeof(Nullable<>).MakeGenericType(TypeToConvert);

        // Done - no conversion
        return null;
    }

दूसरी विधि केवल यह बताती है कि क्या दिया गया प्रकार अशक्त है। इस विधि को पहले कहा जाता है और अलग से उपयोगी है:

    /// <summary>
    /// [ <c>public static bool IsTypeNullable(Type TypeToTest)</c> ]
    /// <para></para>
    /// Reports whether a given Type is nullable (Nullable&lt; Type &gt;)
    /// </summary>
    /// <param name="TypeToTest">The Type to test</param>
    /// <returns>
    /// true = The given Type is a Nullable&lt; Type &gt;; false = The type is not nullable, or <paramref name="TypeToTest"/> 
    /// is null.
    /// </returns>
    /// <remarks>
    /// This method tests <paramref name="TypeToTest"/> and reports whether it is nullable (i.e. whether it is either a 
    /// reference type or a form of the generic Nullable&lt; T &gt; type).
    /// </remarks>
    /// <seealso cref="GetNullableType"/>
    public static bool IsTypeNullable(Type TypeToTest)
    {
        // Abort if no type supplied
        if (TypeToTest == null)
            return false;

        // If this is not a value type, it is a reference type, so it is automatically nullable
        //  (NOTE: All forms of Nullable<T> are value types)
        if (!TypeToTest.IsValueType)
            return true;

        // Report whether TypeToTest is a form of the Nullable<> type
        return TypeToTest.IsGenericType && TypeToTest.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

उपरोक्त IsTypeNullable कार्यान्वयन हर बार एक विजेता की तरह काम करता है, लेकिन यह अपने अंतिम कोड लाइन में थोड़ा वर्बोज़ और धीमा है। निम्नलिखित कोड निकाय IsTypeNullable के लिए ऊपर के समान है, अंतिम कोड लाइन को छोड़कर सरल और तेज है:

        // Abort if no type supplied
        if (TypeToTest == null)
            return false;

        // If this is not a value type, it is a reference type, so it is automatically nullable
        //  (NOTE: All forms of Nullable<T> are value types)
        if (!TypeToTest.IsValueType)
            return true;

        // Report whether an underlying Type exists (if it does, TypeToTest is a nullable Type)
        return Nullable.GetUnderlyingType(TypeToTest) != null;

का आनंद लें!

निशान

पुनश्च - "अशक्तता" के बारे में

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

रन-टाइम (वेब ​​सेवाओं, रिमोट कॉल, डेटाबेस, फीड इत्यादि) तक संभवतया अज्ञात प्रकार की वस्तुओं का उपयोग करने वाली प्रणाली में, एक सामान्य आवश्यकता यह निर्धारित करने के लिए है कि क्या किसी नल को वस्तु को सौंपा जा सकता है, या क्या वस्तु शामिल हो सकती है एक अशक्त। गैर-अशक्त प्रकारों पर इस तरह के ऑपरेशनों को निष्पादित करने से आमतौर पर अपवाद उत्पन्न होंगे, जो प्रदर्शन और कोडिंग आवश्यकताओं के संदर्भ में बहुत महंगे हैं। इस तरह की समस्याओं से बचने के लिए अत्यधिक पसंदीदा दृष्टिकोण लेने के लिए, यह निर्धारित करना आवश्यक है कि क्या एक मनमाना प्रकार का ऑब्जेक्ट अशक्त होने में सक्षम है; यानी, चाहे वह आम तौर पर 'अशक्त' हो।

एक बहुत ही व्यावहारिक और विशिष्ट अर्थ में, .NET की शर्तों में अशक्तता बिल्कुल नहीं है कि किसी वस्तु का प्रकार अशक्त का एक प्रकार है। वास्तव में कई मामलों में, वस्तुओं में संदर्भ प्रकार होते हैं, इसमें एक अशक्त मूल्य हो सकता है, और इस तरह सभी अशक्त होते हैं; इनमें से कोई भी अशक्त प्रकार नहीं है। इसलिए, अधिकांश परिदृश्यों में व्यावहारिक उद्देश्यों के लिए, अशक्तता की सामान्य अवधारणा, बनाम अशक्त की कार्यान्वयन-निर्भर अवधारणा के लिए परीक्षण किया जाना चाहिए। इसलिए हमें केवल .NET Nullable प्रकार पर ध्यान केंद्रित करके नहीं लटकाया जाना चाहिए, बल्कि सामान्यता, व्यावहारिकता की व्यावहारिक अवधारणा पर ध्यान केंद्रित करने की प्रक्रिया में इसकी आवश्यकताओं और व्यवहार की हमारी समझ को शामिल करना चाहिए।


9

लिमन का जवाब बहुत अच्छा है और इससे मुझे मदद मिली है, हालांकि, एक और बग है जिसे ठीक करने की आवश्यकता है।

Nullable.GetUnderlyingType(type)केवल तभी बुलाया जाना चाहिए यदि प्रकार पहले से ही Nullableटाइप नहीं है। अन्यथा, यह गलत तरीके से वापस लौटने के लिए लगता है जब प्रकार से व्युत्पन्न होता है System.RuntimeType(जैसे कि जब मैं गुजरता हूं typeof(System.Int32))। नीचे का संस्करण यह Nullable.GetUnderlyingType(type)जाँचने से परहेज करता है कि क्या प्रकार Nullableइसके बजाय है।

नीचे आपको ExtensionMethodइस विधि का एक संस्करण मिलेगा, जो तुरंत टाइप करेगा जब तक कि यह ValueTypeपहले से ही नहीं है Nullable।

Type NullableVersion(this Type sourceType)
{
    if(sourceType == null)
    {
        // Throw System.ArgumentNullException or return null, your preference
    }
    else if(sourceType == typeof(void))
    { // Special Handling - known cases where Exceptions would be thrown
        return null; // There is no Nullable version of void
    }

    return !sourceType.IsValueType
            || (sourceType.IsGenericType
               && sourceType.GetGenericTypeDefinition() == typeof(Nullable<>) )
        ? sourceType
        : typeof(Nullable<>).MakeGenericType(sourceType);
}

(मुझे खेद है, लेकिन मैं लाइमैन के जवाब पर टिप्पणी नहीं कर सकता क्योंकि मैं नया था और अभी तक पर्याप्त प्रतिनिधि नहीं था।)


2

वहाँ कुछ भी नहीं बनाया गया है कि मुझे पता है, के रूप में int?, आदि के लिए बस वाक्यात्मक चीनी है Nullable<T>; और उस से परे विशेष उपचार नहीं दिया गया है। यह विशेष रूप से संभावना नहीं है कि आप इसे दिए गए प्रकार की जानकारी से प्राप्त करने का प्रयास कर रहे हैं। आमतौर पर कि हमेशा एक के रूप में कुछ 'अपने स्वयं के रोल' कोड की आवश्यकता होती है। Nullableइनपुट प्रकार के पैरामीटर के साथ एक नया प्रकार बनाने के लिए आपको प्रतिबिंब का उपयोग करना होगा ।

संपादित करें: जैसा कि टिप्पणी से पता चलता है कि वास्तव Nullable<> में विशेष रूप से व्यवहार किया जाता है, और इस लेख में बताया गया है ।


Actaully, मुझे पूरा यकीन है कि CLR में Nullable <> के कुछ अलग तरीके से निपटने के लिए कुछ विशेष जादू है। मुझे इसकी जांच करनी होगी।
— ट्रामापॉनी

मुझे इसमें दिलचस्पी होगी, मैं मानता हूं कि अगर यह मामला गलत है तो मुझे खुशी होगी :-)
— ljs

चूंकि आप ऑपरेटर के int?माध्यम से दो जोड़ सकते हैं +, हम जानते हैं कि Nullableविशेष उपचार मिलता है क्योंकि इस तरह का सामान्य ऑपरेटर ओवरलोडिंग अन्यथा काम नहीं करेगा।
— कोनराड रुडोल्फ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.