कैसे जांचा जाए कि कोई वस्तु अशक्त है या नहीं?


202

अगर किसी दिए गए ऑब्जेक्ट को दूसरे शब्दों में कैसे बताया जा सकता है कि मैं कैसे जांच करूं कि निम्नलिखित विधि को कैसे लागू किया जाए ...

bool IsNullableValueType(object o)
{
    ...
}

संपादित करें: मैं अशक्त मूल्य प्रकारों की तलाश कर रहा हूं। मेरे मन में रेफ के प्रकार नहीं थे।

//Note: This is just a sample. The code has been simplified 
//to fit in a post.

public class BoolContainer
{
    bool? myBool = true;
}

var bc = new BoolContainer();

const BindingFlags bindingFlags = BindingFlags.Public
                        | BindingFlags.NonPublic
                        | BindingFlags.Instance
                        ;


object obj;
object o = (object)bc;

foreach (var fieldInfo in o.GetType().GetFields(bindingFlags))
{
    obj = (object)fieldInfo.GetValue(o);
}

obj अब प्रकार के ऑब्जेक्ट को संदर्भित करता है bool( System.Boolean) के बराबर मूल्य के साथ true। जो मैं वास्तव में चाहता था वह एक प्रकार की वस्तु थीNullable<bool>

तो अब एक काम के रूप में मैंने यह जांचने का फैसला किया कि क्या ओ अशक्त है और ओब्जे के आसपास एक अशक्त आवरण बना।


क्या कोड में अशक्त होने के रूप में तार शामिल होने चाहिए? वे एक गैर-जेनेरिक वैल्यू टाइप हैं जो अशक्त प्रतीत होता है। या वे एक वैल्यू टाइप नहीं हैं?
तमसुराजॉय

स्ट्रिंग एक वैल्यू टाइप नहीं है। यह एक संदर्भ प्रकार है।
सनकैट

यह एक बहुत अच्छा सवाल है! 'Type.IsNullableType ()' एक प्रकार का धोखा है क्योंकि यह वास्तव में केवल 'Nullable <T>' प्रकार की जाँच करता है, जो अपेक्षित परिणाम नहीं लौटाता है यदि आप वास्तव में किसी भी प्रकार की जाँच करना चाहते हैं जो अशक्त स्वीकार कर सकता है मान (जैसे मैंने a.IsNullableType () के साथ उपयोग करने की कोशिश की, जहां 'a' एक 'टाइपोफ़ (स्ट्रिंग)' रनटाइम पर निर्धारित किया गया था)
ErrCode

जवाब फ़ील्ड में है। Info.FieldType: जांचें कि क्या फ़ील्ड टाइप सामान्य है और सामान्य प्रकार अशक्त <> प्रकार का है। (उदाहरण: यदि (FieldType.IsGenericType && FieldType.GetGenericTypeDefinition () == टाइपोफ़ (अशक्त <>))। Obj.GetType () प्राप्त करने का प्रयास न करें, इसमें Nullable <T> वेरिएबल T (वेरिएबल प्रकार के बजाय बूलियन प्रकार के मामले में), यह एक बॉक्सिंग समस्या है।
SoLaR

जवाबों:


271

दो प्रकार के अशक्त हैं - Nullable<T>और संदर्भ-प्रकार।

जॉन ने मुझे सही किया है कि यदि बॉक्सिंग किया जाता है तो टाइप करना मुश्किल है, लेकिन आप जेनरिक के साथ कर सकते हैं: - तो नीचे कैसे। यह वास्तव में परीक्षण प्रकार है T, लेकिन objजेनेरिक प्रकार की निष्कासन (कॉल करने में आसान बनाने के लिए) के लिए पूरी तरह से पैरामीटर का उपयोग करते हुए - यह objपरम के बिना लगभग समान रूप से काम करेगा ।

static bool IsNullable<T>(T obj)
{
    if (obj == null) return true; // obvious
    Type type = typeof(T);
    if (!type.IsValueType) return true; // ref-type
    if (Nullable.GetUnderlyingType(type) != null) return true; // Nullable<T>
    return false; // value-type
}

लेकिन यह इतनी अच्छी तरह से काम नहीं करेगा यदि आपने पहले ही किसी ऑब्जेक्ट वैरिएबल पर बॉक्स लगा दिया है।

Microsoft प्रलेखन: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type


7
अंतिम पंक्ति केवल तभी मान्य होती है जब आप किसी तरह से बॉक्सिंग Nullable <T> को सीधे टी बॉक्सिंग के बजाय प्राप्त करने का प्रबंधन करते हैं। यह संभव है, लेकिन जो मुझे याद है उससे प्राप्त करने के लिए मुश्किल।
जॉन स्कीट

यह कोड मेरे लिए मददगार था, इसलिए नहीं कि मुझे एक बॉक्सिंग Nullable <T> मिला, बल्कि इसलिए कि मैं एक सामान्य WPF कनवर्टर बेस क्लास लिख रहा था और कुछ प्रॉपर्टीज़ nullable हैं, इसलिए मैंने उस केस और एक्टीवेटर का पता लगाने के लिए Nullable.GetUnderlyingType का उपयोग किया। एक बॉक्सिंग nullable, (Convert.ChangeType nullables btw को हैंडल नहीं करता है)।
क्वर्टी जू

1
@ यदि आप का मतलब है कि वह अपने प्रकार को स्पष्ट करने के लिए संपादित करता है कि उसने संदर्भ प्रकारों पर विचार नहीं किया है, तो मुझे लगता है कि मेरा उत्तर उस संपादन से पहले था; पाठक वहाँ अपने स्वयं के निर्णय, अपनी जरूरतों के आधार पर, मुझे लगता है कर सकते हैं (इस बात की पुष्टि: उसकी टिप्पणी फिर रेफरी-प्रकार के रूप में 14:42 पर जोड़ा, मेरा जवाब सभी <= 14:34 था)
मार्क Gravell

1
जब obj = 1 होगा तो (obj == null) एक अपवाद फेंक देंगे?
क्यूई फैन

3
@JustinMorgan यदि Tकिसी सामान्य पैरामीटर द्वारा विवश है T : struct, तो Tहोने की अनुमति नहीं है Nullable<>, इसलिए आपको उस मामले में कोई जांच करने की आवश्यकता नहीं है! मुझे पता है कि प्रकार Nullable<>एक संरचना है, लेकिन सी # में बाधा where T : structविशेष रूप से अशक्त मूल्य-प्रकारों को बाहर करती है। युक्ति कहती है: "ध्यान दें कि हालांकि एक मूल्य प्रकार के रूप में वर्गीकृत किया गया है, एक अशक्त प्रकार (:4.1.10) मूल्य प्रकार की बाधा को संतुष्ट नहीं करता है।"
जेपी स्टिग नीलसन 14

46

विधि अधिभार का उपयोग करके एक बहुत ही सरल समाधान है

http://deanchalk.com/is-it-nullable/

अंश:

public static class ValueTypeHelper
{
    public static bool IsNullable<T>(T t) { return false; }
    public static bool IsNullable<T>(T? t) where T : struct { return true; }
}

फिर

static void Main(string[] args)
{
    int a = 123;
    int? b = null;
    object c = new object();
    object d = null;
    int? e = 456;
    var f = (int?)789;
    bool result1 = ValueTypeHelper.IsNullable(a); // false
    bool result2 = ValueTypeHelper.IsNullable(b); // true
    bool result3 = ValueTypeHelper.IsNullable(c); // false
    bool result4 = ValueTypeHelper.IsNullable(d); // false
    bool result5 = ValueTypeHelper.IsNullable(e); // true
    bool result6 = ValueTypeHelper.IsNullable(f); // true

7
आप के लिए प्लस एक परीक्षण के मामलों को जोड़ने के लिए सर। मैंने अन्य सभी उत्तरों की जाँच के लिए उन परीक्षण मामलों का उपयोग किया है। अधिक लोगों को यह अतिरिक्त बिट जाना चाहिए।
मार्टी नील

4
इसके लायक क्या है, यह VB.NET में काम नहीं करता है। इसके परिणामस्वरूप " ओवरलोड रिज़ॉल्यूशन विफल हो गया, क्योंकि सभी स्थितियों में कोई भी सुलभ 'IsNullable' इन तर्कों के लिए सबसे विशिष्ट नहीं हैTrue
ckittel

1
मैं वास्तव में इस समाधान को पसंद करता हूं - और यह शर्म की बात है कि वीबी इसे संभाल नहीं सकता है। मैंने ValueType के साथ काम करने की कोशिश की, लेकिन VB कंपाइलर के साथ असंगत होने के कारण परेशान हो गया, जिसके बारे में ओवरलोड का उपयोग इस आधार पर किया गया था कि क्या इसे साझा विधि या एक्सटेंशन के रूप में कहा जाता है, मैंने इसके बारे में एक सवाल भी उठाया, क्योंकि यह अजीब लगता है: stackoverflow.com/ प्रश्न / 12319591 /…
जेम्स

22
आप संकलन-समय प्रकार की जाँच कर रहे हैं , लेकिन यदि संकलन-समय प्रकार अशक्त है ( System.Nullable<>) तो यह पहले से ही स्पष्ट है (intellisense से )। यदि आप कहते हैं object g = e;और फिर ValueTypeHelper.IsNullable(g), आप क्या प्राप्त करने की उम्मीद करते हैं?
जेपी स्टिग नीलसन

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

30

का प्रश्न "कैसे जाँच करें कि क्या कोई प्रकार अशक्त है?" वास्तव में "कैसे एक प्रकार है अगर जाँच करने के लिए Nullable<>?", जो सामान्य किया जा सकता है "कैसे जाँचें कि क्या एक प्रकार कुछ सामान्य प्रकार का एक निर्मित प्रकार है?", ताकि यह न केवल सवाल का जवाब " Nullable<int>एक है Nullable<>?" लेकिन यह भी " List<int>है List<>?"।

अधिकांश प्रदान किए गए समाधान Nullable.GetUnderlyingType()विधि का उपयोग करते हैं , जो स्पष्ट रूप से केवल मामले के साथ काम करेंगे Nullable<>। मैंने सामान्य चिंतनशील समाधान नहीं देखा जो किसी भी सामान्य प्रकार के साथ काम करेगा, इसलिए मैंने इसे पोस्टरिटी के लिए यहां जोड़ने का फैसला किया, भले ही इस प्रश्न का उत्तर बहुत पहले ही दिया गया हो।

यदि एक प्रकार के कुछ फार्म है जांच करने के लिए Nullable<>प्रतिबिंब का उपयोग कर, आप पहली बार अपने निर्माण सामान्य प्रकार उदाहरण के लिए, परिवर्तित करने के लिए है Nullable<int>, सामान्य प्रकार परिभाषा में, Nullable<>। आप कक्षा की GetGenericTypeDefinition()विधि का उपयोग करके ऐसा कर सकते हैं Type। तब आप परिणामी प्रकार की तुलना इस प्रकार कर सकते हैं Nullable<>:

Type typeToTest = typeof(Nullable<int>);
bool isNullable = typeToTest.GetGenericTypeDefinition() == typeof(Nullable<>);
// isNullable == true

उसी को किसी भी सामान्य प्रकार पर लागू किया जा सकता है:

Type typeToTest = typeof(List<int>);
bool isList = typeToTest.GetGenericTypeDefinition() == typeof(List<>);
// isList == true

कई प्रकार समान हो सकते हैं, लेकिन विभिन्न प्रकार के तर्कों का अर्थ है कि यह पूरी तरह से भिन्न प्रकार का है।

Type typeToTest = typeof(Action<DateTime, float>);
bool isAction1 = typeToTest.GetGenericTypeDefinition() == typeof(Action<>);
bool isAction2 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,>);
bool isAction3 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,,>);
// isAction1 == false
// isAction2 == true
// isAction3 == false

चूंकि Typeऑब्जेक्ट को एक बार प्रति टाइप किया जाता है, आप उनके बीच संदर्भ समानता की जांच कर सकते हैं। इसलिए यदि आप जांचना चाहते हैं कि क्या दो वस्तुएं एक ही सामान्य प्रकार की परिभाषा की हैं, तो आप लिख सकते हैं:

var listOfInts = new List<int>();
var listOfStrings = new List<string>();

bool areSameGenericType =
    listOfInts.GetType().GetGenericTypeDefinition() ==
    listOfStrings.GetType().GetGenericTypeDefinition();
// areSameGenericType == true

यदि आप यह जांचना चाहते हैं कि क्या कोई वस्तु अशक्त होने के बजाय एक योग्य है Type, तो आप मार्क ग्रेवेल के समाधान के साथ उपरोक्त तकनीक का उपयोग कर सकते हैं बल्कि एक सरल विधि बना सकते हैं:

static bool IsNullable<T>(T obj)
{
    if (!typeof(T).IsGenericType)
        return false;

    return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>);
}

@ AllonGuralnek मेरे उत्तर में सरल संस्करण है। मैं इसे संपादित के रूप में बनाना चाहता था और चूंकि मेरी प्रतिष्ठा आपका स्तर नहीं है, यह आपके उत्तर के बिना मेरे नाम के बिना संपादित किया जाएगा, फिर भी, ऐसा लगता है कि समीक्षा मेरे पैर में शूटिंग कर रही है, कि यह लेखक को पसंद है, भले ही यह था नहीं। अजीब दुनिया है, कुछ लोगों को परिभाषाएं नहीं मिलती हैं :)।
ipavlu

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

@ AllonGuralnek स्थिर सामान्य वर्ग और स्थिर एक बार आरंभिक क्षेत्र, जो जटिल है? प्रिय भगवान, मैंने भयानक अपराध किया :)।
ipavlu

@ipavku: हाँ, क्योंकि यह सवाल के साथ कुछ नहीं करना है कि "कैसे जांचा जाए कि कोई वस्तु अशक्त है?"। मैं इसे सरल और बिंदु पर रखने की कोशिश करता हूं, और मैं अनावश्यक और असंबंधित अवधारणाओं को पेश करने से बचता हूं।
एलन जुरनेलक

1
@nffal: अगर मैं आपको सही तरीके से समझ पाया, तो आपके Nullable.GetUnderlyingType()द्वारा पहले से ही उपलब्ध कराए गए ढांचे के सामने अपना कार्यान्वयन खोज रहा है । सिर्फ फ्रेमवर्क में विधि का उपयोग क्यों न करें? हां, तुम्हें करना चाहिए। यह स्पष्ट, अधिक संक्षिप्त और बेहतर परीक्षण है। लेकिन अपनी पोस्ट में मैं यह सिखाने की कोशिश कर रहा हूं कि आप जो जानकारी चाहते हैं उसे पाने के लिए प्रतिबिंब का उपयोग कैसे करें, ताकि कोई इसे किसी भी प्रकार ( typeof(Nullable<>)किसी अन्य प्रकार के साथ प्रतिस्थापित करके ) पर लागू कर सके । आप के स्रोतों को देखें, तो GetUnderlyingType()(मूल या decompiled), आप इसे देखेंगे बहुत मेरी कोड के समान है।
एलोन गुरलीनक

30

यह मेरे लिए काम करता है और सरल लगता है:

static bool IsNullable<T>(T obj)
{
    return default(T) == null;
}

मूल्य प्रकारों के लिए:

static bool IsNullableValueType<T>(T obj)
{
    return default(T) == null && typeof(T).BaseType != null && "ValueType".Equals(typeof(T).BaseType.Name);
}

7
इसके लायक क्या है, यह भी Microsoft द्वारा उपयोग किया जाने वाला
canton7

1
अच्छा ... क्या यह शीर्ष उत्तर कारण नहीं है जो बाद में आया? मुझे शीर्ष उत्तर इतना भ्रामक लगता है।
विंसेंट बसकेरलो

1
यह शीर्ष उत्तर होना चाहिए। विभिन्न तरीकों की कोशिश करने के दिनों के बाद, मैंने इस समाधान के बारे में बेतरतीब ढंग से सोचा, इसकी कोशिश की, और यह पूरी तरह से काम कर रहा है (शीर्ष-रेटेड उत्तर की तुलना में)
user3163495

2
यह पता लगाने के लिए एक उत्कृष्ट समाधान है कि क्या किसी भी उदाहरण को NULL पर सेट किया जा सकता है, लेकिन यह उन सभी चीजों के लिए सही होगा जो सामान्य वस्तुओं सहित, अशक्त करने के लिए सेट की जा सकती हैं। यह महसूस करना महत्वपूर्ण है कि मूल प्रश्न विशेष रूप से Nullable ValueTypes का पता लगाना चाहता था।
जेम्सहॉक्स

20

खैर, आप उपयोग कर सकते हैं:

return !(o is ValueType);

... लेकिन एक वस्तु स्वयं अशक्त या अन्यथा नहीं है - एक प्रकार है। आप इसका उपयोग करने की योजना कैसे बना रहे थे?


2
यह मुझे थोड़ा दूर फेंक दिया। उदाहरण के लिए? i = 5; टाइपऑफ़ (i) रिटर्न सिस्टम। मैं Nullable के बजाय <Int32> - typeof (int?) रिटर्न Nullable <Int32> .. इस विषय पर मुझे कुछ स्पष्टता कहां से मिल सकती है?
गिशु

2
टाइपोफ़ (i) एक संकलक त्रुटि देगा- आप टाइपो का उपयोग किसी चर के साथ नहीं कर सकते। आपने वास्तव में क्या किया?
जॉन स्कीट

15
i.GetType () पहले ऑब्जेक्ट के लिए बॉक्स करेगा, और बॉक्सिंग नॉलेबल टाइप जैसी कोई चीज नहीं है - Nullable <int> एक बॉक्स के लिए एक अशक्त संदर्भ या बॉक्सिंग इंट में जाता है।
जॉन स्कीट

यह तरीका Nullable.GetUnderlyingType (प्रकार) = null से बेहतर है
किवनीत

@Kiquenet: हमारे यहाँ टाइप नहीं है - सिर्फ मूल्य।
जॉन स्कीट

11

सबसे आसान तरीका मैं समझ सकता हूं:

public bool IsNullable(object obj)
{
    Type t = obj.GetType();
    return t.IsGenericType 
        && t.GetGenericTypeDefinition() == typeof(Nullable<>);
}

+1। बॉक्सिंग नल-सक्षम प्रकारों के लिए उत्कृष्ट समाधान। मैंने विशेष रूप से अभी तक इसका परीक्षण नहीं किया है। इसलिए अगर कोई और सत्यापित कर सकता है, तो इसकी सराहना की जाएगी।
तमसुजॉयस

मैंने पहले ही इसका परीक्षण कर लिया है। मुझे एक प्रकार का Nullableप्रकार बनाना था, लेकिन विभिन्न शब्दार्थों के साथ। मेरी स्थिति में मुझे nullएक वैध मूल्य के रूप में समर्थन करना चाहिए और किसी भी मूल्य का समर्थन नहीं करना चाहिए । तो एक Optionalप्रकार बनाया । जैसा कि nullमूल्यों का समर्थन करना आवश्यक था , मुझे Nullableअपने कार्यान्वयन के हिस्से के रूप में मूल्यों को संभालने के लिए कोड भी लागू करना था। यहीं से यह कोड आया।
कार्लोस 13

9
मुझे लगता है कि यह समाधान गलत है। एक अशक्त मान प्रकार के तर्क को एक विधि के रूप में पास करने से यह अपेक्षा की जाती है कि किस प्रकार के ऑब्जेक्ट के पैरामीटर से बॉक्सिंग उत्पन्न हो। अशक्त एक मूल्य प्रकार है और बॉक्सिंग रूपांतरण का परिणाम एक संदर्भ प्रकार है। कोई बॉक्सिंग नल नहीं हैं। मेरा मानना ​​है कि यह तरीका हमेशा गलत होता है?
मिशाक्स

1
इसके बारे में कोई भी परीक्षण अन्य उत्तरों की तरह?
किवनीत

5
यह बॉक्सिंग मूल्य के कारण काम नहीं करता है। यह हमेशा FALSE लौटाएगा।
एन रॉकिंग

10

यहां दो मुद्दे हैं: 1) यह देखने के लिए परीक्षण करना कि क्या एक प्रकार अशक्त है; और 2) यह देखने के लिए परीक्षण करना कि कोई वस्तु अशक्त प्रकार का प्रतिनिधित्व करती है या नहीं।

समस्या 1 (एक प्रकार का परीक्षण) के लिए, यहां एक समाधान है जिसे मैंने अपने सिस्टम में उपयोग किया है: TypeIsNullable-check solution

समस्या 2 (किसी ऑब्जेक्ट का परीक्षण) के लिए, डीन चाक का समाधान मूल्य प्रकारों के लिए काम करता है, लेकिन यह संदर्भ प्रकारों के लिए काम नहीं करता है, क्योंकि <T> अधिभार का उपयोग करने से हमेशा गलत रिटर्न मिलता है। चूंकि संदर्भ प्रकार स्वाभाविक रूप से अशक्त हैं, इसलिए संदर्भ प्रकार का परीक्षण हमेशा सही होना चाहिए। कृपया इन शब्दार्थों की व्याख्या के लिए नीचे [["अशक्तता"] नोट देखें। इस प्रकार, यहाँ डीन के दृष्टिकोण के लिए मेरा संशोधन है:

    public static bool IsObjectNullable<T>(T obj)
    {
        // If the parameter-Type is a reference type, or if the parameter is null, then the object is always nullable
        if (!typeof(T).IsValueType || obj == null)
            return true;

        // Since the object passed is a ValueType, and it is not null, it cannot be a nullable object
        return false; 
    }

    public static bool IsObjectNullable<T>(T? obj) where T : struct
    {
        // Always return true, since the object-type passed is guaranteed by the compiler to always be nullable
        return true;
    }

और यहाँ उपरोक्त समाधान के लिए ग्राहक-परीक्षण कोड में मेरा संशोधन है:

    int a = 123;
    int? b = null;
    object c = new object();
    object d = null;
    int? e = 456;
    var f = (int?)789;
    string g = "something";

    bool isnullable = IsObjectNullable(a); // false 
    isnullable = IsObjectNullable(b); // true 
    isnullable = IsObjectNullable(c); // true 
    isnullable = IsObjectNullable(d); // true 
    isnullable = IsObjectNullable(e); // true 
    isnullable = IsObjectNullable(f); // true 
    isnullable = IsObjectNullable(g); // true

कारण यह है कि मैंने IsObjectNullable <T> (T t) में डीन के दृष्टिकोण को संशोधित किया है, यह है कि उनका मूल दृष्टिकोण हमेशा संदर्भ प्रकार के लिए गलत है। चूँकि IsObjectNullable जैसी विधि को संदर्भ प्रकार मान को संभालने में सक्षम होना चाहिए और चूँकि सभी संदर्भ प्रकार स्वाभाविक रूप से अशक्त हैं, इसलिए यदि कोई संदर्भ प्रकार या अशक्त पास है, तो विधि हमेशा सही होनी चाहिए।

उपरोक्त दो विधियों को निम्न एकल विधि से बदला जा सकता है और समान आउटपुट प्राप्त कर सकते हैं:

    public static bool IsObjectNullable<T>(T obj)
    {
        Type argType = typeof(T);
        if (!argType.IsValueType || obj == null)
            return true;
        return argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(Nullable<>);
    }

हालाँकि, इस अंतिम, एकल-विधि दृष्टिकोण के साथ समस्या यह है कि जब Nullable <T> पैरामीटर का उपयोग किया जाता है, तो प्रदर्शन प्रभावित होता है। इस एकल विधि की अंतिम पंक्ति को निष्पादित करने में बहुत अधिक प्रोसेसर समय लगता है, क्योंकि कंपाइलर को पहले दिखाए गए दूसरे तरीके को अधिभार चुनने की अनुमति देता है जब एक अशक्त <T> -Type पैरामीटर का उपयोग IsObjectNullable कॉल में किया जाता है। इसलिए, इष्टतम समाधान यहां चित्रित दो-विधि दृष्टिकोण का उपयोग करना है।

CAVEAT: यह विधि मूल रूप से केवल तभी काम करती है जब मूल ऑब्जेक्ट संदर्भ या सटीक प्रतिलिपि का उपयोग करके कहा जाता है, जैसा कि उदाहरणों में दिखाया गया है। हालाँकि, यदि एक अशक्त वस्तु को उसके मूल Nullable <> फ़ॉर्म में शेष रहने के बजाय किसी अन्य प्रकार (जैसे ऑब्जेक्ट, आदि) के लिए बॉक्स किया जाता है, तो यह विधि मज़बूती से काम नहीं करेगी। यदि इस पद्धति को कॉल करने वाला कोड मूल, अनबॉक्स्ड ऑब्जेक्ट संदर्भ या सटीक प्रतिलिपि का उपयोग नहीं कर रहा है, तो यह इस पद्धति का उपयोग करके ऑब्जेक्ट की अशक्तता को मज़बूती से निर्धारित नहीं कर सकता है।

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

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

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

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

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


8

सबसे सरल समाधान जो मैं आया था, वह है Microsoft समाधान को लागू करना ( कैसे: एक अशक्त प्रकार की पहचान करें (C # प्रोग्रामिंग गाइड) ) एक विस्तार विधि के रूप में:

public static bool IsNullable(this Type type)
{
    return Nullable.GetUnderlyingType(type) != null;
}

यह तो जैसे कहा जा सकता है:

bool isNullable = typeof(int).IsNullable();

यह उपयोग करने का एक तार्किक तरीका भी लगता है IsNullable()क्योंकि यह कक्षा के अन्य सभी IsXxxx()तरीकों से फिट बैठता है Type


1
क्या आप "=!" के बजाय "==" का उपयोग नहीं करना चाहते थे?
vkelman

अच्छा स्थान @vkelman उस परिवर्तन को करने के बजाय मैंने Microsoft से वर्तमान सुझाव का उपयोग करने का उत्तर अपडेट कर दिया है क्योंकि मैंने इसे लिखने के बाद इसे बदल दिया है।
sclarke81

6

देखभाल योग्य बनें, जब एक अशक्त प्रकार ( Nullable<int>या उदाहरण के लिए बॉक्सिंग ):

int? nullValue = null;
object boxedNullValue = (object)nullValue;
Debug.Assert(boxedNullValue == null);

int? value = 10;
object boxedValue = (object)value;
Debug.Assert( boxedValue.GetType() == typeof(int))

यह एक सच्चा संदर्भ प्रकार बन जाता है, इसलिए आप इस तथ्य को खो देते हैं कि यह अशक्त था।


3

शायद विषय से थोड़ा हटकर, लेकिन फिर भी कुछ दिलचस्प जानकारी। मुझे बहुत से ऐसे लोग मिलते हैं जो Nullable.GetUnderlyingType() != nullपहचान का उपयोग करते हैं यदि एक प्रकार अशक्त है। यह स्पष्ट रूप से काम करता है, लेकिन Microsoft निम्नलिखित सलाह देता है type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)( http://msdn.microsoft.com/en-us/library/ms366789.aspx देखें )।

मैंने इसे प्रदर्शन के दृष्टिकोण से देखा। नीचे परीक्षण (एक मिलियन प्रयासों) का निष्कर्ष यह है कि जब कोई प्रकार अशक्त होता है, तो Microsoft विकल्प सबसे अच्छा प्रदर्शन देता है।

Nullable.GetUnderlyingType (): 1335ms (3 बार धीमा)

GetGenericTypeDefinition () == टाइपोफ़ (अशक्त <>): 500ms

मुझे पता है कि हम समय की एक छोटी राशि के बारे में बात कर रहे हैं, लेकिन हर कोई मिलिसेकंड्स को ट्विन करना पसंद करता है :-)! इसलिए यदि आप बॉस चाहते हैं कि आप कुछ मिलीसेकंड कम कर दें तो यह आपका उद्धारकर्ता है ...

/// <summary>Method for testing the performance of several options to determine if a type is     nullable</summary>
[TestMethod]
public void IdentityNullablePerformanceTest()
{
    int attempts = 1000000;

    Type nullableType = typeof(Nullable<int>);

    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
    {
        Assert.IsTrue(Nullable.GetUnderlyingType(nullableType) != null, "Expected to be a nullable"); 
    }

    Console.WriteLine("Nullable.GetUnderlyingType(): {0} ms", stopwatch.ElapsedMilliseconds);

    stopwatch.Restart();

    for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
   {
       Assert.IsTrue(nullableType.IsGenericType && nullableType.GetGenericTypeDefinition() == typeof(Nullable<>), "Expected to be a nullable");
   }

   Console.WriteLine("GetGenericTypeDefinition() == typeof(Nullable<>): {0} ms", stopwatch.ElapsedMilliseconds);
   stopwatch.Stop();
}

1
नमस्ते, समय मापने के साथ शायद एक मुद्दा है, एस्टर परिणामों को प्रभावित कर सकता है। क्या आपने एसेस्टर के बिना परीक्षण किया है? इसके अलावा कंसोल.ट्राइटलाइन पैमाइश क्षेत्र के बाहर होना चाहिए। प्रदर्शन के मुद्दों को निर्धारित करने के प्रयास के लिए +1 :)।
ipavlu

@ विप्लव Console.WriteLineवास्तव में पैमाइश क्षेत्र से बाहर है;)
नवाफ़ल

Roel, जैसा कि ipavlu ने उल्लेख किया है, Assertलूप के बाहर होना चाहिए। दूसरे, आपको गैर-अशक्त लोगों के साथ-साथ झूठे मामलों के लिए भी परीक्षण करना चाहिए। मैंने एक समान परीक्षण किया (2 नलिका और 4 गैर-नलिकाएं) और मुझे ~ 2 सेकंड के लिए GetUnderlyingTypeऔर ~ 1 सेकंड के लिए मिलाGetGenericTypeDefinition , यानी, GetGenericTypeDefinitionदो बार तेज है (तीन बार नहीं)।
नवाफल

इस बार 2 नलबल और 2 गैर-नलिकाओं के साथ एक और दौर किया GetUnderlyingType 2.5 गुना धीमा था। केवल गैर-अशक्त के साथ - इस समय दोनों गर्दन और गर्दन हैं।
नवाफ़ल

लेकिन अधिक महत्वपूर्ण बात है कि, GetUnderlyingType उपयोगी है जब आपको अशक्तता के लिए जांच करनी होगी और यदि यह अशक्त है तो अंतर्निहित प्रकार प्राप्त करना होगा। यह बहुत उपयोगी है और आप पैटर्न को अक्सर पसंद करते हैं Activator.CreateInstance(Nullable.GetUnderlyingType(type) ?? type)। यह asकीवर्ड की तरह है , कलाकारों के लिए चेक के साथ-साथ यह परिणाम और वापसी भी करता है। यदि आप अंतर्निहित प्रकार की अशक्त वापस प्राप्त करना चाहते हैं तो एक GetGenericTypeDefinitionचेक करना और फिर सामान्य प्रकार प्राप्त करना एक बुरा विचार होगा। यह भी GetUnderlyingTypeअधिक पठनीय और यादगार है। अगर मैं इसे केवल ~ 1000 बार कर रहा हूं तो मुझे बुरा नहीं लगेगा।
नवाफ़ल

0

यह संस्करण:

  • कैशिंग परिणाम तेज़ है,
  • विधि (टी obj) की तरह अनावश्यक चर की आवश्यकता नहीं है
  • जटिल नहीं :),
  • सिर्फ स्थैतिक सामान्य वर्ग, जिसमें एक बार गणना की गई फ़ील्ड है

:

public static class IsNullable<T>
{
    private static readonly Type type = typeof(T);
    private static readonly bool is_nullable = type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
    public static bool Result { get { return is_nullable; } }
}

bool is_nullable = IsNullable<int?>.Result;

मुझे लगता है कि आपने उस स्थैतिक घोषणा 'is_nullable' के साथ अपने स्वयं के उत्तर दिए। टिप: इंट के साथ ऑब्जेक्ट घोषित करें? (ऑब्जेक्ट ए = (इंट?) 8;) और देखें कि क्या होता है।
SoLaR

0

यहाँ मैं वही कर रहा हूँ, जैसा कि बाकी सब कुछ विफल लग रहा था - कम से कम PLC पर - पोर्टेबल क्लास लाइब्रेरी / .NET कोर के साथ> C # 6

समाधान: किसी भी प्रकार Tऔर के लिए स्थिर तरीकों का विस्तारNullable<T> और तथ्य यह है कि स्थिर विस्तार विधि, अंतर्निहित प्रकार मिलान लागू किया जा करने के लिए जा रहा है और सामान्य पर पूर्वता लेता है का उपयोगT विस्तार-विधि।

के लिए T:

public static partial class ObjectExtension
{
    public static bool IsNullable<T>(this T self)
    {
        return false;
    }
}

और किसके लिए Nullable<T>

public static partial class NullableExtension
{
    public static bool IsNullable<T>(this Nullable<T> self) where T : struct
    {
        return true;
    }
}

type.IsGenericTypeप्रतिक्षेपण का उपयोग करना और ... .NET रनंटाइम के मेरे वर्तमान सेट पर काम नहीं किया। न ही MSDN प्रलेखन में मदद की।

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {…}

भाग में क्योंकि .NET कोर में परावर्तन एपीआई को काफी बदल दिया गया है।


0

मुझे लगता है कि Microsoft के सुझाए गए परीक्षण का उपयोग करने वाले IsGenericTypeअच्छे हैं, लेकिन कोड में GetUnderlyingType, Microsoft यह सुनिश्चित करने के लिए एक अतिरिक्त परीक्षण का उपयोग करता है कि आप सामान्य प्रकार की परिभाषा में पास नहीं हुए हैं Nullable<>:

 public static bool IsNullableType(this Type nullableType) =>
    // instantiated generic type only                
    nullableType.IsGenericType &&
    !nullableType.IsGenericTypeDefinition &&
    Object.ReferenceEquals(nullableType.GetGenericTypeDefinition(), typeof(Nullable<>));

-1

ऐसा करने का एक सरल तरीका:

    public static bool IsNullable(this Type type)
    {
        if (type.IsValueType) return Activator.CreateInstance(type) == null;

        return true;
    }

ये मेरी इकाई परीक्षण हैं और सभी उत्तीर्ण हुए हैं

    IsNullable_String_ShouldReturn_True
    IsNullable_Boolean_ShouldReturn_False
    IsNullable_Enum_ShouldReturn_Fasle
    IsNullable_Nullable_ShouldReturn_True
    IsNullable_Class_ShouldReturn_True
    IsNullable_Decimal_ShouldReturn_False
    IsNullable_Byte_ShouldReturn_False
    IsNullable_KeyValuePair_ShouldReturn_False

वास्तविक इकाई परीक्षण

    [TestMethod]
    public void IsNullable_String_ShouldReturn_True()
    {
        var typ = typeof(string);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Boolean_ShouldReturn_False()
    {
        var typ = typeof(bool);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Enum_ShouldReturn_Fasle()
    {
        var typ = typeof(System.GenericUriParserOptions);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Nullable_ShouldReturn_True()
    {
        var typ = typeof(Nullable<bool>);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Class_ShouldReturn_True()
    {
        var typ = typeof(TestPerson);
        var result = typ.IsNullable();
        Assert.IsTrue(result);
    }

    [TestMethod]
    public void IsNullable_Decimal_ShouldReturn_False()
    {
        var typ = typeof(decimal);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_Byte_ShouldReturn_False()
    {
        var typ = typeof(byte);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }

    [TestMethod]
    public void IsNullable_KeyValuePair_ShouldReturn_False()
    {
        var typ = typeof(KeyValuePair<string, string>);
        var result = typ.IsNullable();
        Assert.IsFalse(result);
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.