2016-01-26 7 views
5

की कॉलिंग विधि मुझे इन दो पहलुओं के बारे में संदेह है;गैर-निर्दिष्ट कक्षा

पहला वाला;

 Test test = new Test(); 

     result = test.DoWork(_param); 

दूसरा एक;

 result = new Test().DoWork(_param); 

क्या होता है यदि हम नव निर्मित उदाहरण को एक चर में निर्दिष्ट नहीं करते हैं और सीधे विधि को कॉल करते हैं?

मुझे आईएल कोड पर दो तरीकों के बीच कुछ अंतर दिखाई देता है।


नीचे यह एक पहला सी # कोड

IL_0000: ldstr  "job " 
IL_0005: stloc.0 
IL_0006: newobj  instance void Works.Test::.ctor() 
IL_000b: stloc.1 
IL_000c: ldloc.1 
IL_000d: ldloc.0 
IL_000e: callvirt instance string Works.Test::DoWork(string) 
IL_0013: pop 
IL_0014: ret 

के आईएल उत्पादन होता है और यह एक सेकंड सी # कोड का आईएल उत्पादन

IL_0000: ldstr  "job " 
IL_0005: stloc.0 
IL_0006: newobj  instance void Works.Test::.ctor() 
IL_000b: ldloc.0 
IL_000c: call  instance string Works.Test::DoWork(string) 
IL_0011: pop 
IL_0012: ret 

आपको सूचित कृपया सकते है मुझे?

+2

एक मामले में आप कॉल के बाद ऑब्जेक्ट तक पहुंच सकते हैं और दूसरे में आप नहीं कर सकते हैं। – AlG

+0

वैसे, दूसरा स्टैक पर आवंटित नहीं होता है। ढेर पर टेस्ट ऑब्जेक्ट का संदर्भ बनाने के बजाय, यह केवल DoWork() को निष्पादित करता है; –

+0

http://stackoverflow.com/questions/12557603/why-can-i-create-an-instance-of-a-class-without-storing-it-to-a-variable-and-sti – Habib

उत्तर

20

प्रश्न यहाँ खोजने के लिए एक छोटा सा मुश्किल है लेकिन मुझे लगता है कि तुम क्या कह रहे हैं यह है:

क्यों एक callvirt उत्पन्न करने के लिए संकलक एक चर कारण करने के लिए नव निर्मित संदर्भ बताए करता है, लेकिन बुला विधि सीधे एक कॉल उत्पन्न करता है?

आप इस सूक्ष्म अंतर को ध्यान में रखते हुए बहुत सावधान हैं।

इससे पहले कि हम आपके प्रश्न पर जाएं, कुछ अन्य सवालों का जवाब दें।

क्या मुझे विश्वास है कि संकलक अच्छा कोड उत्पन्न करता है?

आम तौर पर हां। कभी-कभी कोड जेन बग होते हैं लेकिन यह उनमें से एक नहीं है।

क्या कॉलवर्ट के साथ गैर-वर्चुअल विधि को कॉल करना कानूनी है?

हां।

क्या कॉल के साथ वर्चुअल विधि को कॉल करना कानूनी है?

हां, यदि आप कोशिश कर रहे हैं, तो कहें, व्युत्पन्न कक्षा में ओवरराइड के बजाय बेस क्लास विधि को कॉल करें। लेकिन आमतौर पर ऐसा नहीं होता है।

क्या इस उदाहरण में वर्चुअल या नहीं कहा जा रहा है?

यह वर्चुअल नहीं है।

चूंकि विधि वर्चुअल नहीं है, इसे कॉलवर्ट या कॉल के साथ बुलाया जा सकता है। कभी-कभी संकलक कॉलवर्ट उत्पन्न करता है और कभी-कभी कॉल उत्पन्न करता है, जब यह दोनों बार कॉलवर्ट उत्पन्न कर सकता है या लगातार दोनों बार कॉल कर सकता है?

अब हम आपके प्रश्न का दिलचस्प हिस्सा प्राप्त करते हैं।

कॉल और कॉलवर्ट के बीच दो अंतर हैं।

  • कॉल वर्चुअल प्रेषण नहीं करता है; कॉलवर्ट वर्चुअल फ़ंक्शन प्रेषण तालिका में इसे कॉल करने से पहले सही विधि को देखता है। तो इसलिए कॉलवर्ट एक नैनोसेकंद धीमा है।

  • कॉलवर्ट हमेशा यह जांचता है कि रिसीवर शून्य है, भले ही कहा गया तरीका वर्चुअल है या नहीं। कॉल यह देखने के लिए जांच नहीं करता है कि रिसीवर शून्य है या नहीं। कॉल के माध्यम से एक शून्य "यह" के साथ एक विधि को कॉल करना कानूनी है।

अब शायद आप देखेंगे कि यह कहां जा रहा है।

क्या सी # को एक शून्य संदर्भ रिसीवर पर कॉल किए जाने पर एक शून्य अपरिवर्तनीय अपवाद के साथ क्रैश करने की आवश्यकता है?

हाँ। सी # को क्रैश करने के लिए आवश्यक है जब आप किसी शून्य रिसीवर के साथ कुछ आह्वान करते हैं। इसलिए सी # में विधि को कॉल करने के लिए कोड उत्पन्न करते समय निम्न विकल्पों में से कुछ हैं:

  • केस 1: आईएल जेनरेट करें जो शून्य के लिए जांचता है, फिर कॉल उत्पन्न करता है।
  • केस 2: कॉलवर्ट जेनरेट करें।
  • केस 3: कॉल जेनरेट करें, लेकिन शून्य की जांच से शुरू न करें।

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

केस 2 स्मार्ट है। सी # कंपाइलर कॉलविर्ट उत्पन्न करता है ताकि शून्य जांच स्वचालित रूप से हो।

अब केस 3 के बारे में क्या? किस परिस्थिति में सी # शून्य जांच को छोड़ सकता है और कॉल उत्पन्न कर सकता है?केवल जब:

  • कॉल एक गैर आभासी विधि कॉल है, और
  • सी # पहले से ही जानता है कि रिसीवर रिक्त नहीं है

लेकिन सी # जानता है कि new Foo().Bar() में रिसीवर क्योंकि नल नहीं हो सकता अगर यह था, तो निर्माण एक अपवाद फेंक दिया होगा और हम कभी भी कॉल नहीं करेंगे!

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

कंपाइलर उस स्मार्ट होने के लिए लिखा जा सकता है। संकलक को निश्चित असाइनमेंट जांच के लिए पहले से चर के असाइनमेंट स्टेटस को ट्रैक करना होगा। यह "कुछ ऐसा असाइन किया गया था जो शून्य हो सकता है" राज्य को ट्रैक कर सकता है, और फिर यह दोनों मामलों में एक कॉल उत्पन्न करेगा। लेकिन संकलक (अभी तक) स्मार्ट नहीं है।

+0

हां, निश्चित रूप से मैं यही पूछ रहा हूं। मैंने आधार वर्ग बनाकर 'DoWork' विधि को वर्चुअल में रूपांतरित कर दिया, इस बार इसे' कॉल' के बजाय 'कॉलवर्ट' कहा जाता है। मुझे लगता है कि यह कंपाइलर का चालाक हिस्सा है। –

0

यदि आप कुछ और नहीं करते हैं, तो करने के दो तरीकों के बीच कोई अंतर नहीं है।

एकमात्र वास्तविक अंतर यह है कि पहले मामले में, आप अपने Test आवृत्ति को आवृत्ति पर असाइन करते हैं, ताकि आप इसे बाद में एक्सेस कर सकें/डीबगर में इसका निरीक्षण कर सकें। आप दूसरे मामले में ऐसा नहीं कर सकते हैं।

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

+0

लेकिन आईएल निर्देशों पर कुछ मतभेद हैं, कोई 'कॉलवर्ट' कह रहा है और दूसरा निर्देश 'कॉल' पर कॉल कर रहा है? –