प्रश्न यहाँ खोजने के लिए एक छोटा सा मुश्किल है लेकिन मुझे लगता है कि तुम क्या कह रहे हैं यह है:
क्यों एक callvirt उत्पन्न करने के लिए संकलक एक चर कारण करने के लिए नव निर्मित संदर्भ बताए करता है, लेकिन बुला विधि सीधे एक कॉल उत्पन्न करता है?
आप इस सूक्ष्म अंतर को ध्यान में रखते हुए बहुत सावधान हैं।
इससे पहले कि हम आपके प्रश्न पर जाएं, कुछ अन्य सवालों का जवाब दें।
क्या मुझे विश्वास है कि संकलक अच्छा कोड उत्पन्न करता है?
आम तौर पर हां। कभी-कभी कोड जेन बग होते हैं लेकिन यह उनमें से एक नहीं है।
क्या कॉलवर्ट के साथ गैर-वर्चुअल विधि को कॉल करना कानूनी है?
हां।
क्या कॉल के साथ वर्चुअल विधि को कॉल करना कानूनी है?
हां, यदि आप कोशिश कर रहे हैं, तो कहें, व्युत्पन्न कक्षा में ओवरराइड के बजाय बेस क्लास विधि को कॉल करें। लेकिन आमतौर पर ऐसा नहीं होता है।
क्या इस उदाहरण में वर्चुअल या नहीं कहा जा रहा है?
यह वर्चुअल नहीं है।
चूंकि विधि वर्चुअल नहीं है, इसे कॉलवर्ट या कॉल के साथ बुलाया जा सकता है। कभी-कभी संकलक कॉलवर्ट उत्पन्न करता है और कभी-कभी कॉल उत्पन्न करता है, जब यह दोनों बार कॉलवर्ट उत्पन्न कर सकता है या लगातार दोनों बार कॉल कर सकता है?
अब हम आपके प्रश्न का दिलचस्प हिस्सा प्राप्त करते हैं।
कॉल और कॉलवर्ट के बीच दो अंतर हैं।
कॉल वर्चुअल प्रेषण नहीं करता है; कॉलवर्ट वर्चुअल फ़ंक्शन प्रेषण तालिका में इसे कॉल करने से पहले सही विधि को देखता है। तो इसलिए कॉलवर्ट एक नैनोसेकंद धीमा है।
कॉलवर्ट हमेशा यह जांचता है कि रिसीवर शून्य है, भले ही कहा गया तरीका वर्चुअल है या नहीं। कॉल यह देखने के लिए जांच नहीं करता है कि रिसीवर शून्य है या नहीं। कॉल के माध्यम से एक शून्य "यह" के साथ एक विधि को कॉल करना कानूनी है।
अब शायद आप देखेंगे कि यह कहां जा रहा है।
क्या सी # को एक शून्य संदर्भ रिसीवर पर कॉल किए जाने पर एक शून्य अपरिवर्तनीय अपवाद के साथ क्रैश करने की आवश्यकता है?
हाँ। सी # को क्रैश करने के लिए आवश्यक है जब आप किसी शून्य रिसीवर के साथ कुछ आह्वान करते हैं। इसलिए सी # में विधि को कॉल करने के लिए कोड उत्पन्न करते समय निम्न विकल्पों में से कुछ हैं:
- केस 1: आईएल जेनरेट करें जो शून्य के लिए जांचता है, फिर कॉल उत्पन्न करता है।
- केस 2: कॉलवर्ट जेनरेट करें।
- केस 3: कॉल जेनरेट करें, लेकिन शून्य की जांच से शुरू न करें।
केस 1 बस गूंगा है। आईएल बड़ा है, और इसलिए डिस्क पर अधिक जगह लेती है, लोड करने के लिए धीमी है, जिट के लिए धीमी है। कॉलवर्ट स्वचालित रूप से एक शून्य जांच करता है जब यह कोड उत्पन्न करना मूर्खतापूर्ण होगा।
केस 2 स्मार्ट है। सी # कंपाइलर कॉलविर्ट उत्पन्न करता है ताकि शून्य जांच स्वचालित रूप से हो।
अब केस 3 के बारे में क्या? किस परिस्थिति में सी # शून्य जांच को छोड़ सकता है और कॉल उत्पन्न कर सकता है?केवल जब:
- कॉल एक गैर आभासी विधि कॉल है, और
- सी # पहले से ही जानता है कि रिसीवर रिक्त नहीं है
लेकिन सी # जानता है कि new Foo().Bar()
में रिसीवर क्योंकि नल नहीं हो सकता अगर यह था, तो निर्माण एक अपवाद फेंक दिया होगा और हम कभी भी कॉल नहीं करेंगे!
कंपाइलर इतना समझने के लिए पर्याप्त नहीं है कि चर को केवल गैर-शून्य मान असाइन किए गए हैं। तो यह सुरक्षित होने के लिए एक कॉलवर्ट उत्पन्न करता है।
कंपाइलर उस स्मार्ट होने के लिए लिखा जा सकता है। संकलक को निश्चित असाइनमेंट जांच के लिए पहले से चर के असाइनमेंट स्टेटस को ट्रैक करना होगा। यह "कुछ ऐसा असाइन किया गया था जो शून्य हो सकता है" राज्य को ट्रैक कर सकता है, और फिर यह दोनों मामलों में एक कॉल उत्पन्न करेगा। लेकिन संकलक (अभी तक) स्मार्ट नहीं है।
एक मामले में आप कॉल के बाद ऑब्जेक्ट तक पहुंच सकते हैं और दूसरे में आप नहीं कर सकते हैं। – AlG
वैसे, दूसरा स्टैक पर आवंटित नहीं होता है। ढेर पर टेस्ट ऑब्जेक्ट का संदर्भ बनाने के बजाय, यह केवल DoWork() को निष्पादित करता है; –
http://stackoverflow.com/questions/12557603/why-can-i-create-an-instance-of-a-class-without-storing-it-to-a-variable-and-sti – Habib