2009-08-12 16 views
9

null एक प्रकार है? एक शून्य मूल्य आंतरिक रूप से प्रतिनिधित्व कैसे किया जाता है? निम्नलिखित कोड में क्या हो रहा है?.Net/C# में, निरंतर दृढ़ता से टाइप किया गया है?

void Foo(string bar) {...} 
void Foo(object bar) {...} 

Foo((string)null); 

संपादित करें: अब तक उत्तर अनपेक्षित और उच्च स्तर के हैं। मैं समझता हूं कि एक संदर्भ प्रकार ऑब्जेक्ट में स्टैक पर एक पॉइंटर होता है जो ढेर पर एक स्थान को इंगित करता है जिसमें एक सिंक ब्लॉक इंडेक्स, एक प्रकार हैंडल और ऑब्जेक्ट के फ़ील्ड होते हैं। जब मैं किसी ऑब्जेक्ट का उदाहरण null पर सेट करता हूं, तो स्टैक पर पॉइंटर कहां इंगित करता है, बिल्कुल? और कोड स्निपेट में, सी # कंपाइलर द्वारा आसानी से उपयोग किया जाने वाला कास्ट तय करने के लिए किया जाता है, और वास्तव में कोई भी कास्टिंग चालू नहीं है?

मैं सीएलआर आंतरिकों को समझने वाले किसी व्यक्ति द्वारा गहराई से जवाब ढूंढ रहा हूं।

उत्तर

16

आपके कोड नमूने में string पर कास्ट null एक प्रकार नहीं देता है, क्योंकि null में कोई प्रकार नहीं हो सकता है। आप इस का सबूत चाहते हैं, तो निम्न कोड निष्पादित जैसा कि आप देख सकते हैं कि जहां null हमेशा खुद के बराबर है, भले ही क्या चर इसे करने के लिए सौंपा गया था के प्रकार है की:

string s = null; 
IPAddress i = null; 
Console.WriteLine(object.Equals(s, i)); // prints "True" 
Console.WriteLine(object.ReferenceEquals(s, i)); // prints "True" 

क्या डाली करता है को बयां करती हैं संकलक जो चुनने के लिए अधिभार।null एक प्रकार नहीं है के रूप में यह अधिभार है कि एक object या एक string के रूप में यह मान के रूप में व्याख्या की जा सकती लेता है चुनने के लिए है कि क्या पता नहीं है। तो आप यह कहकर इसे मदद कर रहे हैं "यहां एक शून्य मूल्य है जिसे माना जाना चाहिए कि यह एक स्ट्रिंग था"।


यदि आप देखना चाहते हैं कि नीचे क्या हो रहा है, तो अपने कोड से आईएल देखें। विधि कॉल के लिए प्रासंगिक बिट शाब्दिक आईएल में निम्नलिखित की तरह कुछ है (आदि अपने नाम स्थान और वर्ग के नाम के आधार पर,):

ldnull 
call void ConsoleApplication1.Program::Foo(string) 

तो वह सब हो रहा है कि एक अशक्त ढेर पर लोड किया जा रहा है, और तो यह ओवरलोड द्वारा खपत होता है जो स्ट्रिंग लेता है, क्योंकि ओवरलोड रिज़ॉल्यूशन संकलन समय पर किया जाता है, इसलिए कॉल करने की विधि आईएल में बेक जाती है।

आप को देखने के लिए क्या ldnull करता चाहते हैं, और क्यों यह सिर्फ ldc.i4.0 की तरह कुछ का उपयोग कर एक शून्य ढेर पर लोड करने के लिए तो this answer देख (यदि आप कड़ी का अनुसरण नहीं करना चाहते से अलग है, तो कारण यह है कि है एक आकार-अज्ञेय शून्य जो अन्यथा सीएलआर में मौजूद नहीं है)।

+0

तो जब मैं 'शून्य' का जिक्र कर रहा हूं तो स्टैक पर वास्तव में क्या होगा? –

+0

@ मैट - अधिक निम्न स्तर के विवरण जोड़ने के लिए संपादित किया गया। क्या यह पर्याप्त है? –

+0

@ ग्रेग: धन्यवाद - मैं काम पर व्यस्त था इसलिए आईएल और ईसीएमए खुद को जांचने का समय नहीं था। इसने मेरे बौद्धिक खुजली खरोंच की है। –

2

यह फू (स्ट्रिंग बार) को कॉल करेगा।

आप शून्य ठीक कर सकते हैं।

+0

जाहिर है - कृपया मेरा संपादन देखें। –

1

अशक्त कीवर्ड एक शाब्दिक कि एक अशक्त संदर्भ, एक है कि किसी भी वस्तु का उल्लेख नहीं करता प्रतिनिधित्व करता है। शून्य संदर्भ-प्रकार चर के डिफ़ॉल्ट मान है। MSDN से। तो आपके उदाहरण में स्ट्रिंग का डिफ़ॉल्ट मान।

// A null string is not the same as an empty string. 
string s = null; 
string t = String.Empty; // Logically the same as "" 

क्या आप कर रहे हैं प्रति ऊपर के रूप में डिफ़ॉल्ट का उपयोग कर के बराबर है:

int equal = string.Compare((string)null, default(string)); 
2

जब आप null के लिए एक संदर्भ ऑब्जेक्ट सेट, सूचक (पीछे) स्मृति में एक विशेष स्थान के लिए अंक कि null नामित है। तो जब आप null पर जाते हैं, तो आप वास्तव में विशिष्ट प्रकार का सूचक बनाते हैं जो null पर इंगित करता है।

दूसरों (1)(2) द्वारा प्रदर्शन के रूप में, इस मामले में हो प्रतीत नहीं होता है क्योंकि संकलक ओवरलोडिंग विशिष्ट null कलाकारों के अनुसार आईएल उत्सर्जक हल करता है।

मुझे पता है कि संदर्भ चर के साथ उनके साथ एक प्रकार है। मैंने सोचा कि यह null कास्टिंग के पीछे होगा लेकिन मैं गलत था।

ldnull opcode एक अशक्त संदर्भ (ग्रुप ओ) ढेर पर धक्का। और, भले ही इस शून्य संदर्भ में इसके साथ जुड़े प्रकार हैं, call इस संदर्भ को string के वैध तर्क के रूप में स्वीकार करता है। कम से कम, यह मेरी समझ है। अगर किसी के पास कोई सुधार है तो कृपया मुझे सही करने के लिए स्वतंत्र महसूस करें।

1

NULL एक मार्कर है, इसमें डेटा प्रकार नहीं है। जब आप किसी फ़ील्ड या चर के लिए .NULL असाइन करते हैं, तो मान NULL में बदल जाता है लेकिन फ़ील्ड या चर का डेटा प्रकार परिवर्तित नहीं होता है।

स्ट्रिंग प्रकार को आपके उदाहरण में शून्य करने का कारण मुझे लगता है कि चुड़ैल विधि का उपयोग करने के लिए यह उपयोग किया जाएगा (इस मामले में "शून्य फू (स्ट्रिंग बार) {...}" क्योंकि यह तरीका है तर्कों के रूप तार स्वीकार करता है)

आप फू ((वस्तु) अशक्त बुलाया चाहते हैं)। अन्य विधि का उपयोग किया जाएगा। ("शून्य फू (ऑब्जेक्ट बार) {...}")

6

शून्य के पास प्रकार नहीं है, और "और कोड स्निपेट में, सी # कंपाइलर द्वारा उपयोग की जाने वाली कास्ट है यह तय करने के लिए कि किस ओवरलोड को कॉल करना है, और वास्तव में कोई भी कास्टिंग नहीं है? " ठीक है क्या चल रहा है। आइए जेनरेटेड आईएल देखें।

IL_0001: ldnull 
    IL_0002: call  void ConsoleApplication1.Program::Foo(string) 

स्टैक पर ldnull लोडिंग शून्य को नोटिस करें। यह बस एक स्ट्रिंग या कुछ और के रूप में शून्य नहीं है, शून्य है। दूसरी बात क्या मायने रखती है, जहां आईएल स्पष्ट रूप से ओवरलोड को कॉल कर रहा है जो स्ट्रिंग प्राप्त करता है। यहाँ आपत्ति उठाने कास्टिंग, क्या होता है अगर आप कहते हैं:

IL_0001: ldnull 
    IL_0002: call  void ConsoleApplication1.Program::Foo(object) 

तो, हाँ, डाली एक सी # विरूपण साक्ष्य तो संकलक जानता है क्या कॉल करने के लिए ओवरलोड है।

1

null मूल्य के प्रकार ECMA-334 द्वारा इस प्रकार परिभाषित किया गया है:

11.2.7 अशक्त प्रकार

अशक्त शाब्दिक (§9.4.4.6) अशक्त मूल्य, का मूल्यांकन जो एक संदर्भ किसी भी वस्तु या सरणी, या एक मूल्य के अभाव पर इंगित नहीं निरूपित किया जाता है। शून्य प्रकार का एक मान है, जो शून्य मान है। इसलिए एक अभिव्यक्ति जिसका प्रकार अशक्त प्रकार केवल शून्य मान का मूल्यांकन कर सकते हैं। कोई रास्ता नहीं स्पष्ट रूप से अशक्त प्रकार लिख सकते हैं और, इसलिए, कोई रास्ता नहीं घोषित प्रकार में उपयोग करना नहीं है।

अशक्त प्रकार प्रकार पदानुक्रम के निचले भाग प्रकार है - वस्तु के पीछे; शून्य प्रकार को प्रत्येक शून्य प्रकार के उप-प्रकार के रूप में सोचा जा सकता है, क्योंकि जहां भी कोई शून्य न हो तो शून्य मूल्य का उपयोग किया जा सकता है।

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

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

संबंधित मुद्दे