C # में ऑब्जेक्ट्स कभी भी स्कोप से बाहर नहीं जाते हैं क्योंकि वे C ++ में करते हैं। जब वे अब उपयोग नहीं किए जाते हैं तो वे स्वचालित रूप से कचरा कलेक्टर द्वारा निपटाए जाते हैं। यह C ++ से अधिक जटिल दृष्टिकोण है जहां एक चर का दायरा पूरी तरह से नियतात्मक है। सीएलआर कचरा कलेक्टर सक्रिय रूप से उन सभी वस्तुओं से गुजरता है जो बनाई गई हैं और यदि उनका उपयोग किया जा रहा है तो काम करता है।
एक वस्तु एक फ़ंक्शन में "स्कोप से बाहर" जा सकती है, लेकिन यदि उसका मान वापस आ जाता है, तो जीसी यह देखेगा कि कॉलिंग फ़ंक्शन रिटर्न वैल्यू पर है या नहीं।
ऑब्जेक्ट संदर्भ सेट करना null
अनावश्यक है क्योंकि कचरा संग्रह काम करता है जो वस्तुओं को अन्य वस्तुओं द्वारा संदर्भित किया जाता है।
व्यवहार में, आपको विनाश के बारे में चिंता करने की ज़रूरत नहीं है, यह सिर्फ काम करता है और यह बहुत अच्छा है :)
Dispose
उन सभी ऑब्जेक्ट्स पर कॉल किया जाना चाहिए जो IDisposable
तब लागू होते हैं जब आप उनके साथ काम कर रहे होते हैं। आम तौर पर आप using
उन वस्तुओं के साथ एक ब्लॉक का उपयोग करेंगे जैसे:
using (var ms = new MemoryStream()) {
//...
}
संपादित करेंचर गुंजाइश पर । क्रेग ने पूछा है कि क्या चर दायरे का वस्तु जीवनकाल पर कोई प्रभाव पड़ता है। सीएलआर के उस पहलू को ठीक से समझाने के लिए, मुझे C ++ और C # से कुछ अवधारणाओं को समझाने की आवश्यकता होगी।
वास्तविक चर गुंजाइश
दोनों भाषाओं में चर का उपयोग केवल उसी दायरे में किया जा सकता है जब इसे परिभाषित किया गया था - वर्ग, कार्य या ब्रेस द्वारा संलग्न एक स्टेटमेंट ब्लॉक। हालाँकि, सूक्ष्म अंतर यह है कि C # में, चरों को एक नेस्टेड ब्लॉक में पुनर्परिभाषित नहीं किया जा सकता है।
C ++ में, यह पूरी तरह से कानूनी है:
int iVal = 8;
//iVal == 8
if (iVal == 8){
int iVal = 5;
//iVal == 5
}
//iVal == 8
C # में, हालांकि आपको एक कंपाइलर त्रुटि मिलती है:
int iVal = 8;
if(iVal == 8) {
int iVal = 5; //error CS0136: A local variable named 'iVal' cannot be declared in this scope because it would give a different meaning to 'iVal', which is already used in a 'parent or current' scope to denote something else
}
यह समझ में आता है यदि आप उत्पन्न MSIL को देखते हैं - फ़ंक्शन द्वारा उपयोग किए जाने वाले सभी चर फ़ंक्शन के प्रारंभ में परिभाषित किए गए हैं। इस समारोह पर एक नज़र डालें:
public static void Scope() {
int iVal = 8;
if(iVal == 8) {
int iVal2 = 5;
}
}
नीचे उत्पन्न आईएल है। ध्यान दें कि iVal2, जिसे अगर ब्लॉक के अंदर परिभाषित किया गया है, तो वास्तव में फ़ंक्शन स्तर पर परिभाषित किया गया है। प्रभावी रूप से इसका मतलब है कि C # में केवल वर्ग और फ़ंक्शन स्तर की गुंजाइश है जहां तक चर जीवनकाल का संबंध है।
.method public hidebysig static void Scope() cil managed
{
// Code size 19 (0x13)
.maxstack 2
.locals init ([0] int32 iVal,
[1] int32 iVal2,
[2] bool CS$4$0000)
//Function IL - omitted
} // end of method Test2::Scope
सी ++ गुंजाइश और वस्तु जीवनकाल
जब भी C ++ वैरिएबल, स्टैक पर आवंटित किया जाता है, तो वह स्कोप से बाहर हो जाता है और वह नष्ट हो जाता है। याद रखें कि C ++ में आप स्टैक पर या ढेर पर ऑब्जेक्ट बना सकते हैं। जब आप उन्हें स्टैक पर बनाते हैं, तो एक बार निष्पादन गुंजाइश छोड़ देता है, वे स्टैक से पॉपप हो जाते हैं और नष्ट हो जाते हैं।
if (true) {
MyClass stackObj; //created on the stack
MyClass heapObj = new MyClass(); //created on the heap
obj.doSomething();
} //<-- stackObj is destroyed
//heapObj still lives
जब सी ++ ऑब्जेक्ट्स को ढेर पर बनाया जाता है, तो उन्हें स्पष्ट रूप से नष्ट कर दिया जाना चाहिए, अन्यथा यह एक मेमोरी लीक है। हालांकि स्टैक चर के साथ ऐसी कोई समस्या नहीं है।
सी # ऑब्जेक्ट लाइफटाइम
CLR में, ऑब्जेक्ट्स (अर्थात संदर्भ प्रकार) हमेशा प्रबंधित हीप पर बनाए जाते हैं । यह ऑब्जेक्ट निर्माण सिंटैक्स द्वारा आगे प्रबलित है। इस कोड स्निपेट पर विचार करें।
MyClass stackObj;
C ++ में यह MyClass
स्टैक पर एक इंस्टेंस बनाएगा और इसके डिफॉल्ट कंस्ट्रक्टर को कॉल करेगा। C # में यह वर्ग के लिए एक संदर्भ पैदा करेगा MyClass
जो किसी भी चीज़ की ओर इशारा नहीं करता है। new
ऑपरेटर का उपयोग करके किसी वर्ग की आवृत्ति बनाने का एकमात्र तरीका है :
MyClass stackObj = new MyClass();
एक तरह से, C # ऑब्जेक्ट बहुत सी ऐसी वस्तुएं हैं जो new
C ++ में सिंटैक्स का उपयोग करके बनाई गई हैं - वे ढेर पर बनाई गई हैं लेकिन C ++ ऑब्जेक्ट्स के विपरीत, वे रनटाइम द्वारा प्रबंधित की जाती हैं, इसलिए आपको उन्हें नष्ट करने के बारे में चिंता करने की ज़रूरत नहीं है।
चूँकि वस्तुएं हमेशा इस तथ्य पर होती हैं कि ऑब्जेक्ट रेफ़रेंस (यानी पॉइंटर्स) दायरे से बाहर हो जाते हैं, तो वे मूट हो जाते हैं। यह निर्धारित करने में अधिक कारक शामिल हैं कि क्या किसी वस्तु को केवल वस्तु के संदर्भ में मौजूदगी से एकत्र किया जाए।
C # ऑब्जेक्ट संदर्भ
जॉन स्कीट ने जावा में ऑब्जेक्ट के संदर्भों की तुलना स्ट्रिंग के टुकड़ों से की जो गुब्बारे से जुड़े होते हैं, जो कि वस्तु है। समान सादृश्य C # ऑब्जेक्ट संदर्भों पर लागू होता है। वे बस ढेर के एक स्थान को इंगित करते हैं जिसमें ऑब्जेक्ट होता है। इस प्रकार, इसे शून्य पर सेट करने से वस्तु के जीवनकाल पर कोई तत्काल प्रभाव नहीं पड़ता है, गुब्बारा मौजूद रहता है, जब तक कि जीसी "पॉप" नहीं करता।
गुब्बारा सादृश्य को जारी रखते हुए, यह तर्कसंगत प्रतीत होगा कि एक बार गुब्बारे में कोई तार नहीं जुड़ा होता है, इसे नष्ट किया जा सकता है। वास्तव में यह ठीक इसी तरह से है कि गिनती की गई वस्तुएं गैर-प्रबंधित भाषाओं में काम करती हैं। इस दृष्टिकोण को छोड़कर परिपत्र संदर्भों के लिए बहुत अच्छी तरह से काम नहीं करता है। दो गुब्बारों की कल्पना करें जो एक तार द्वारा एक साथ जुड़े हुए हैं लेकिन न तो गुब्बारे में किसी और चीज के लिए एक स्ट्रिंग है। सरल री-काउंटिंग नियमों के तहत, वे दोनों मौजूद हैं, भले ही पूरा गुब्बारा समूह "अनाथ" हो।
.NET ऑब्जेक्ट्स एक छत के नीचे हीलियम गुब्बारे की तरह हैं। जब छत खुलती है (जीसी चलता है) - अप्रयुक्त गुब्बारे दूर तैरते हैं, भले ही गुब्बारे के समूह हो सकते हैं जो एक साथ मिलकर होते हैं।
.NET GC, जेनेशनल GC और मार्क और स्वीप के संयोजन का उपयोग करता है। पीढ़ीगत दृष्टिकोण में उन वस्तुओं का निरीक्षण करने के लिए रनटाइम का पक्ष शामिल है जिन्हें हाल ही में आवंटित किया गया है, क्योंकि वे अप्रयुक्त होने की अधिक संभावना है और मार्क और स्वीप में रनटाइम पूरे ऑब्जेक्ट ग्राफ के माध्यम से जा रहा है और अगर ऑब्जेक्ट ऑब्जेक्ट्स अप्रयुक्त हैं तो बाहर काम करना शामिल है। यह पर्याप्त रूप से परिपत्र निर्भरता समस्या से संबंधित है।
इसके अलावा, .NET GC दूसरे थ्रेड (जिसे अंतिम रूप से थ्रेड कहा जाता है) पर चलता है क्योंकि इसमें मुख्य थ्रेड पर ऐसा करने और करने के लिए काफी कुछ है जो आपके प्रोग्राम को बाधित करेगा।