C # में डिस्ट्रॉयर बनाम डिस्ट्रॉक्टर का उपयोग करने में क्या अंतर है?


101

मैं एक विध्वंसक के विपरीत एक वर्ग पर IDispose कब लागू करूंगा? मैंने इस लेख को पढ़ा , लेकिन मैं अभी भी इस बिंदु को याद कर रहा हूं।

मेरी धारणा यह है कि अगर मैं किसी वस्तु पर आईडीसपोज को लागू करता हूं, तो मैं स्पष्ट रूप से इसे नष्ट करने के लिए प्रतीक्षा करने के लिए विरोध के रूप में इसे 'विनाश' कर सकता हूं। क्या ये सही है?

इसका मतलब यह है कि मुझे हमेशा स्पष्ट रूप से एक वस्तु पर निपटान कॉल करना चाहिए? इसके कुछ सामान्य उदाहरण क्या हैं?


5
दरअसल, आपको हर डिस्पोजेबल ऑब्जेक्ट पर Dispose को कॉल करना चाहिए। आप आसानी से usingनिर्माण का उपयोग कर सकते हैं ।
ल्यूक टॉराइले

आह, यह समझ में आता है। मैं हमेशा सोचता था कि 'स्टेटमेंट' का इस्तेमाल फाइल धाराओं के लिए क्यों किया गया। मुझे पता है कि इसका उद्देश्य वस्तु के दायरे से कुछ लेना-देना था, लेकिन मैंने इसे आईडीसॉर्पोरेट इंटरफ़ेस के संदर्भ में नहीं रखा।
जॉर्डन पार्मर 14

5
याद रखने के लिए एक महत्वपूर्ण बिंदु यह है कि एक अंतिम रूप से किसी वर्ग के किसी भी प्रबंधित सदस्य तक कभी नहीं पहुंचना चाहिए , क्योंकि वे सदस्य अब मान्य संदर्भ नहीं हो सकते हैं।
दान ब्रायंट

जवाबों:


126

एक फाइनल (उर्फ डिस्ट्रॉक्टर) कचरा संग्रह (जीसी) का हिस्सा है - यह अनिश्चित है जब (या यहां तक ​​कि) ऐसा होता है, क्योंकि जीसी मुख्य रूप से स्मृति दबाव (यानी अधिक स्थान की आवश्यकता) के परिणामस्वरूप होता है। फाइनल आमतौर पर केवल अप्रबंधित संसाधनों की सफाई के लिए उपयोग किया जाता है , क्योंकि प्रबंधित संसाधनों का अपना संग्रह / निपटान होगा।

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

इस पर पिछले विषयों के बहुत सारे हैं:

अंत में, ध्यान दें कि किसी IDisposableवस्तु के लिए यह भी असामान्य नहीं है कि उसका अंतिम रूप भी हो; इस मामले में, Dispose()आमतौर पर कॉल किया जाता है GC.SuppressFinalize(this), जिसका अर्थ है कि GC अंतिम रूप से नहीं चलता है - यह केवल मेमोरी को दूर फेंकता है (बहुत सस्ता)। यदि आप Dispose()ऑब्जेक्ट को भूल जाते हैं तो फ़ाइनलीज़र फिर भी चलता है ।


धन्यवाद! यह सही समझ में आता है। मैं बहुत अच्छी प्रतिक्रिया की सराहना करता हूं।
जॉर्डन पैमर 14

27
एक अतिरिक्त बात कहना चाहता हूँ। जब तक आप वास्तव में एक की जरूरत नहीं है, तब तक अपनी कक्षा में एक अंतिम रूप न जोड़ें। यदि आप एक फाइनल (विध्वंसक) जोड़ते हैं, तो जीसी को इसे (यहां तक ​​कि एक खाली फाइनलर) भी कॉल करना होगा और इसे कॉल करने के लिए ऑब्जेक्ट हमेशा एक जीन 1 कचरा संग्रह से बचेगा। यह जीसी को बाधित और धीमा कर देगा। यही कारण है कि मार्क मार्क कहते हैं कि उपरोक्त कोड में SuppressFinalize
केविन जोन्स

1
इसलिए अंतिम रूप से अप्रबंधित संसाधनों को जारी करना है। लेकिन प्रबंधित और अप्रबंधित संसाधनों को जारी करने के लिए डिस्पोज़ का उपयोग किया जा सकता है?
Dark_Knight

2
@ डक हां; क्योंकि प्रबंधन श्रृंखला के 6 स्तर एक अप्रबंधित हो सकते हैं जो शीघ्र सफाई की आवश्यकता है
मार्क ग्रेवेल

1
@ केविनजोन की वस्तुओं को अंतिम रूप देने वाले को जीन 0 से बचने की गारंटी दी जाती है, न कि 1 को? मैंने इसे .NET परफॉर्मेंस नामक पुस्तक में पढ़ा।
डेविड क्लेम्फनर

25

Finalize()विधि की भूमिका यह सुनिश्चित करना है कि कचरा एकत्र होने पर एक .NET ऑब्जेक्ट अप्रबंधित संसाधनों को साफ कर सकता है । हालांकि, कचरा संग्रहण पर निर्भर होने के बजाय, डेटाबेस कनेक्शन या फ़ाइल हैंडलर जैसी वस्तुओं को जल्द से जल्द जारी किया जाना चाहिए। उसके लिए आपको IDisposableइंटरफ़ेस लागू करना चाहिए , और अपने संसाधनों को Dispose()विधि में जारी करना चाहिए ।


9

MSDN पर बहुत अच्छा वर्णन है :

इस इंटरफ़ेस का प्राथमिक उपयोग मानव रहित संसाधनों को जारी करना है । कचरा संग्रहकर्ता स्वचालित रूप से एक प्रबंधित वस्तु को आवंटित स्मृति को जारी करता है जब उस वस्तु का उपयोग नहीं किया जाता है। हालांकि, यह अनुमान लगाना संभव नहीं है कि कचरा संग्रह कब होगा । इसके अलावा, कचरा संग्रहकर्ता को अप्रबंधित संसाधनों जैसे खिड़की के हैंडल, या खुली फाइलों और धाराओं का कोई ज्ञान नहीं है।

कचरे के संग्रहकर्ता के साथ संयोजन में अप्रबंधित संसाधनों को स्पष्ट रूप से जारी करने के लिए इस इंटरफ़ेस के निपटान विधि का उपयोग करें । किसी ऑब्जेक्ट का उपभोक्ता इस विधि को कॉल कर सकता है जब ऑब्जेक्ट की आवश्यकता नहीं होती है।


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

1
यदि एक अल्पकालिक वस्तु लंबे समय तक रहने वाली वस्तु से एक घटना की सदस्यता लेती है (जैसे कि यह किसी भी परिवर्तन की सूचना देता है जो अल्पकालिक वस्तु के जीवनकाल के भीतर होती है), इस तरह की घटना को एक अप्रबंधित संसाधन माना जाना चाहिए, क्योंकि विफलता के बाद से इस घटना को अनसब्सक्राइब करने का कारण लंबे समय तक जीवित वस्तु के लिए अल्पकालिक वस्तु का जीवनकाल होगा। यदि कई हजारों या लाखों अल्पकालिक वस्तुओं को एक घटना के लिए सब्सक्राइब किया जाता है, लेकिन बिना सदस्यता के छोड़ दिया जाता है, तो इससे मेमोरी या सीपीयू रिसाव हो सकता है (क्योंकि प्रत्येक सदस्यता को संसाधित करने के लिए आवश्यक समय बढ़ जाएगा)।
सुपरकैट

1
प्रबंधित कोड में अप्रबंधित संसाधनों को शामिल करने वाला एक अन्य परिदृश्य पूल से वस्तु आवंटन होगा। विशेष रूप से यदि कोड को .NET माइक्रो फ्रेमवर्क में चलाने की आवश्यकता है (जिसका कचरा कलेक्टर डेस्कटॉप मशीनों पर एक की तुलना में बहुत कम कुशल है) यह कोड के लिए सहायक हो सकता है उदाहरण के लिए संरचनाओं की एक सरणी, जिनमें से प्रत्येक को "उपयोग" चिह्नित किया जा सकता है या "मुक्त"। एक आबंटन अनुरोध को एक संरचना मिलनी चाहिए जो वर्तमान में "मुक्त" के रूप में चिह्नित है, इसे "उपयोग" चिह्नित करें, और इसे एक सूचकांक लौटाएं; एक रिलीज अनुरोध "मुक्त" के रूप में एक संरचना को चिह्नित करना चाहिए। यदि कोई आवंटन अनुरोध 23 उदाहरण के लिए रिटर्न देता है, तो ...
सुपरकैट

1
... यदि कोड उस सरणी के स्वामी को कभी सूचित नहीं करता है जिसे अब आइटम # 23 की आवश्यकता नहीं है, तो वह सरणी स्लॉट किसी अन्य कोड द्वारा कभी भी उपयोग करने योग्य नहीं होगा। सरणी स्लॉट्स के बाहर इस तरह के मैनुअल आवंटन का उपयोग डेस्कटॉप कोड में बहुत बार नहीं किया जाता है क्योंकि जीसी काफी कुशल है, लेकिन माइक्रो फ्रेमवर्क पर चल रहे कोड में यह बहुत बड़ा बदलाव ला सकता है।
सुपरकैट

8

केवल एक चीज जो C # डिस्ट्रक्टर में होनी चाहिए वह है यह लाइन:

Dispose(False);

बस। उस विधि में और कुछ नहीं होना चाहिए।


3
यह .NET के प्रलेखन में Microsoft द्वारा प्रस्तावित डिज़ाइन पैटर्न है, लेकिन इसका उपयोग तब न करें, जब आपकी वस्तु IDisposable नहीं है। msdn.microsoft.com/en-us/library/fs2xkftw%28v=vs.110%29.aspx
Zbyl

1
मैं किसी भी कारण के साथ एक अंतिम प्रस्ताव के साथ एक वर्ग की पेशकश करने के बारे में सोच भी नहीं सकता है जिसमें डिस्पोज़ विधि भी नहीं है।
जोनाथन एलन

4

आपके द्वारा हमेशा कॉल किया जाना चाहिए या नहीं, इस बारे में आपका प्रश्न Disposeआमतौर पर एक गर्म बहस है। .NET समुदाय में सम्मानित व्यक्तियों के दिलचस्प परिप्रेक्ष्य के लिए इस ब्लॉग को देखें ।

व्यक्तिगत रूप से, मुझे लगता है कि जेफरी रिक्टर की स्थिति यह है कि कॉलिंग Disposeअनिवार्य नहीं है, अविश्वसनीय रूप से कमजोर है। वह अपनी राय को सही ठहराने के लिए दो उदाहरण देता है।

पहले उदाहरण में वे कहते हैं कि Disposeविंडोज फॉर्म्स पर नियंत्रण मुख्यधारा के परिदृश्य में थकाऊ और अनावश्यक है। हालांकि, वह यह उल्लेख करने में विफल रहता है कि Disposeवास्तव में उन मुख्यधारा के परिदृश्यों में नियंत्रण कंटेनरों द्वारा स्वचालित रूप से कहा जाता है।

दूसरे उदाहरण में वे कहते हैं कि एक डेवलपर गलत तरीके से मान सकता है कि इस उदाहरण को IAsyncResult.WaitHandleआक्रामक रूप से यह महसूस किए बिना निपटाया जाना चाहिए कि संपत्ति आलसी रूप से प्रतीक्षा प्रदर्शन को रोकती है जिसके परिणामस्वरूप अनावश्यक प्रदर्शन जुर्माना लगाया जाता है। लेकिन, इस उदाहरण के साथ समस्या यह है कि IAsyncResultखुद IDisposableवस्तुओं से निपटने के लिए Microsoft के अपने स्वयं के प्रकाशित दिशानिर्देशों का पालन नहीं करता है । यदि कोई वर्ग किसी प्रकार का संदर्भ रखता है IDisposableतो कक्षा को ही लागू करना चाहिए IDisposable। अगर IAsyncResultउस नियम का पालन किया जाता है, तो इसका अपना Disposeतरीका यह निर्णय ले सकता है कि उसके कौन से घटक सदस्यों को निपटाने की जरूरत है।

इसलिए जब तक किसी के पास अधिक सम्मोहक तर्क नहीं है, मैं "हमेशा कॉल डिस्पोज़" शिविर में रहने वाला हूं इस समझ के साथ कि कुछ फ्रिंज मामले होने वाले हैं जो ज्यादातर खराब डिजाइन विकल्पों में से उत्पन्न होते हैं।


3

यह वास्तव में बहुत आसान है। मुझे पता है कि इसका उत्तर दिया गया है लेकिन मैं फिर से कोशिश करूंगा लेकिन इसे यथासंभव सरल रखने की कोशिश करूंगा।

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

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

फ़ाइनलीज़र के निष्पादित होने पर अधिकांश कक्षाएं निपटान को कॉल करेंगी लेकिन यह बस एक सुरक्षित गार्ड के रूप में है और इसे कभी भी भरोसा नहीं करना चाहिए। जब आप इसके साथ काम कर रहे हों, तो आपको स्पष्ट रूप से कुछ भी निपटाना चाहिए जो IDisposable को लागू करता है। यदि आप आईडीआईएसओपी को लागू करते हैं, तो आपको अंतिम रूप में निपटान को कॉल करना चाहिए। एक उदाहरण के लिए http://msdn.microsoft.com/en-us/library/system.idisposable.aspx देखें ।


नहीं, कचरा संग्राहक कभी भी Dispose () नहीं कहता है। इसे ही फाइनल कहते हैं।
मार्क Gravell

तय किया कि कक्षाओं को अपने फाइनल में निपटान को कॉल करना चाहिए, लेकिन उनके पास नहीं है।
डेगले

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.