अंतिम रूप बनाम विवाद


215

कुछ लोग Finalizeविधि के ऊपर विधि का उपयोग क्यों करते हैं Dispose?

आप किन स्थितियों में Finalizeविधि का उपयोग करेंगे Disposeऔर इसके विपरीत?


जवाबों:


121

दूसरों ने पहले से ही अंतर को कवर किया है Disposeऔर Finalize(btw Finalizeविधि को अभी भी भाषा विनिर्देश में विध्वंसक कहा जाता है), इसलिए मैं उन परिदृश्यों के बारे में थोड़ा जोड़ूंगा जहां Finalizeविधि काम में आती है।

कुछ प्रकार एक प्रकार से डिस्पोजेबल संसाधनों को इनकैप्सुलेट करते हैं, जहाँ एक ही क्रिया में उनका उपयोग और निपटान करना आसान होता है। सामान्य उपयोग अक्सर इस तरह होता है: खुला, पढ़ा या लिखना, बंद (निपटान)। यह usingनिर्माण के साथ बहुत अच्छी तरह से फिट बैठता है ।

दूसरों को थोड़ा और मुश्किल होता है। WaitEventHandlesउदाहरणों के लिए इस तरह का उपयोग नहीं किया जाता है क्योंकि वे एक धागे से दूसरे में संकेत देने के लिए उपयोग किए जाते हैं। सवाल तो यह है कि Disposeइन पर किसे फोन करना चाहिए ? इस तरह के एक सुरक्षा प्रकार के रूप में Finalize, एक विधि को लागू करते हैं , जो सुनिश्चित करता है कि संसाधनों का निपटान तब किया जाता है जब उदाहरण को अनुप्रयोग द्वारा संदर्भित नहीं किया जाता है।


60
मैं इस स्वीकृत उत्तर को नहीं समझ सका। मैं अब भी अलग जानना चाहता हूं। यह क्या है?
इस्माइल

22
@ इस्माईल: सबसे बड़ी स्थिति जहाँ Finalizeउचित ठहराया जा सकता है, जब ऐसी कई वस्तुएं होती हैं जो किसी संसाधन को जीवित रखने में रुचि रखती हैं, लेकिन ऐसा कोई साधन नहीं है जिसके द्वारा संसाधन में दिलचस्पी रखने वाली कोई वस्तु पता चल सके कि क्या यह पता चल सकता है? आखरी। ऐसे मामले में, Finalizeआमतौर पर केवल तभी फायर किया जाएगा जब किसी की वस्तु में दिलचस्पी न हो। Finalizeफ़ाइलों और ताले जैसे गैर-कवक संसाधनों के लिए समय की ढीली अवधि भयानक है, लेकिन कवक संसाधनों के लिए ठीक हो सकता है।
सुपरकैट

13
एक महान नए (मेरे लिए) शब्द के लिए +1 सुपरकैट। संदर्भ ने इसे बहुत स्पष्ट कर दिया है, लेकिन सिर्फ हम में से बाकी के मामले में, यहां विकिपीडिया कहता है: "फंगिबिलिटी एक अच्छे या एक कमोडिटी की संपत्ति है जिसकी व्यक्तिगत इकाइयां पारस्परिक प्रतिस्थापन के लिए सक्षम हैं, जैसे कि मीठा कच्चा तेल, शेयरों में एक कंपनी, बॉन्ड, कीमती धातुएँ, या मुद्राएँ। "
जॉन कूम्स

5
@JonCoombs: यह बहुत ज्यादा सही है, हालांकि यह ध्यान देने योग्य है कि शब्द "फंगसिबल रिसोर्स" को उन चीजों पर लागू किया जाता है जो स्वतंत्र रूप से प्रतिस्थापित होने तक स्वतंत्र रूप से प्रतिस्थापित हो जाते हैं और रिलीज या परित्याग के बाद फिर से स्वतंत्र रूप से प्रतिस्थापित हो जाते हैं । यदि सिस्टम में लॉक ऑब्जेक्ट्स का एक पूल है और कोड एक को प्राप्त करता है जिसे वह किसी इकाई के साथ संबद्ध करता है, तो जब तक कोई भी धारण कर रहा है , उस लॉक को उस इकाई के साथ जोड़ने के उद्देश्य से एक संदर्भ , उस लॉक को प्रतिस्थापित नहीं किया जा सकता है कोई और। यदि सभी कोड जो पहरेदार इकाई के बारे में परवाह करते हैं, हालांकि, ताला बंद कर देता है, ...
सुपरकैट

... तो यह फिर से स्वतंत्र रूप से प्रतिस्थापित हो जाएगा जब तक कि यह किसी अन्य इकाई के साथ जुड़ा हुआ है।
सुपरकैट

135

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

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

मानक अभ्यास को लागू करना है IDisposableऔर Disposeताकि आप किसी वस्तु में अपनी वस्तु का उपयोग कर सकें using। इस तरह के रूप में using(var foo = new MyObject()) { }। और आपके फ़ाइनलीज़र में, आप कॉल करते हैं Dispose, यदि कॉलिंग कोड आपको निपटाना भूल गया है।


17
आपको अपने अंतिम कार्यान्वयन से निपटान को कॉल करने के बारे में थोड़ा सावधान रहने की आवश्यकता है - निपटान प्रबंधित संसाधनों को भी निपटान कर सकता है, जिसे आप अपने फाइनल से नहीं छूना चाहते हैं, क्योंकि वे पहले से ही खुद को अंतिम रूप दे सकते हैं।
itowlson

6
@itowlson: वस्तुओं को दो बार निपटाया जा सकता है, इस धारणा के साथ संयुक्त अशक्त के लिए जाँच (दूसरी कॉल कुछ भी नहीं करने के साथ) काफी अच्छी होनी चाहिए।
सैमुअल

7
मानक आईडीसपोजिशन पैटर्न और प्रबंधित घटकों को निपटाने के लिए डिस्पोजल (बूल) के छिपे हुए कार्यान्वयन को उस समस्या के लिए वैकल्पिक लगता है।
ब्रूडी

ऐसा लगता है कि विध्वंसक (~ MyClass () विधि) को लागू करने का कोई कारण नहीं है और हमेशा डिस्पोज़ () विधि को लागू करना और कॉल करना है। या मैं गलत हूँ? क्या कोई मुझे एक उदाहरण दे सकता है जब दोनों को लागू किया जाना चाहिए?
dpelisek

66

अंतिम रूप एक बैकस्टॉप विधि है, जिसे कचरा कलेक्टर द्वारा बुलाया जाता है जब वह किसी वस्तु को पुनः प्राप्त करता है। निपटान "निर्धारक सफाई" विधि है, जिसे बहुमूल्य देशी संसाधनों (खिड़की के हैंडल, डेटाबेस कनेक्शन, आदि) को जारी करने के लिए अनुप्रयोगों द्वारा बुलाया जाता है, जब उन्हें अब ज़रूरत नहीं होती, बजाय उन्हें अनिश्चित काल तक पकड़े रहने के बजाय जब तक कि जीसी वस्तु के लिए गोल न हो जाए।

ऑब्जेक्ट के उपयोगकर्ता के रूप में, आप हमेशा डिस्पोज़ का उपयोग करते हैं। जीसी के लिए अंतिम रूप है।

एक वर्ग के कार्यान्वयनकर्ता के रूप में, यदि आप प्रबंधित संसाधनों को पकड़ते हैं, जिन्हें निपटाना है, तो आप निपटान को लागू करते हैं। यदि आप मूल संसाधन रखते हैं, तो आप Dispose and Finalize दोनों को कार्यान्वित करते हैं, और दोनों एक सामान्य विधि कहते हैं जो मूल संसाधनों को जारी करती है। इन मुहावरों को आम तौर पर एक निजी डिस्पोज़ल (बूल डिस्पोज़िंग) विधि के माध्यम से जोड़ा जाता है, जो कॉल को सही के साथ डिस्पोज़ करता है, और झूठी के साथ कॉल को अंतिम रूप देता है। यह विधि हमेशा मूल संसाधनों को मुक्त करती है, फिर डिस्पोज़ करने वाले पैरामीटर की जांच करती है, और यदि यह सही है तो प्रबंधित संसाधनों का निपटान करता है और GC.SuppressFinalize को कॉल करता है।


उदाहरण के लिए देखें msdn.microsoft.com/en-us/library/vstudio/… और stackoverflow.com/questions/898828/…
itowlson

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

2
@ जेकोब्स: Disposeअच्छा है, और इसे सही तरीके से लागू करना आम तौर पर आसान है। Finalizeबुराई है, और इसे सही ढंग से लागू करना आम तौर पर कठिन है। अन्य बातों के अलावा, क्योंकि GC यह सुनिश्चित करेगा कि किसी भी वस्तु की पहचान को कभी "पुनर्नवीनीकरण" नहीं मिलेगा, जब तक कि उस वस्तु का कोई भी संदर्भ मौजूद नहीं है, Disposableवस्तुओं का एक गुच्छा साफ करना आसान है , जिनमें से कुछ को पहले ही साफ किया जा सकता है, कोई दिक्कत नहीं है; किसी वस्तु का कोई संदर्भ जिस Disposeपर पहले ही कॉल किया Disposeजा चुका है, उस वस्तु का संदर्भ रहेगा जिस पर पहले ही कॉल किया जा चुका है।
सुपरकैट

2
@JCoombs: मानव रहित संसाधन, इसके विपरीत, आमतौर पर ऐसी कोई गारंटी नहीं होती है। यदि ऑब्जेक्ट Fredफ़ाइल हैंडल # 42 का मालिक है और इसे बंद कर देता है, तो सिस्टम उसी नंबर को कुछ फ़ाइल हैंडल से संलग्न कर सकता है जो किसी अन्य इकाई को दिया गया है। उस स्थिति में, फ़ाइल हैंडल # 42 फ्रेड की बंद फ़ाइल को संदर्भित नहीं करेगा, लेकिन उस फ़ाइल को जो उस अन्य संस्था द्वारा सक्रिय उपयोग में थी; के लिए Fredबंद करने के # 42 संभाल कोशिश करने के लिए फिर से विनाशकारी होगा। 100% की कोशिश मज़बूती से करें कि क्या एक अप्रबंधित वस्तु को अभी तक जारी किया गया है वह व्यावहारिक है। कई वस्तुओं का ट्रैक रखने की कोशिश बहुत कठिन है।
सुपरकैट

2
@JCoombs: यदि प्रत्येक अप्रबंधित संसाधन को अपनी स्वयं की आवरण वस्तु में रखा जाता है, जो अपने जीवनकाल को नियंत्रित करने के अलावा कुछ नहीं करता है, तो बाहरी कोड जो यह नहीं जानता है कि संसाधन जारी किया गया है, लेकिन यह जानता है कि यह होना चाहिए अगर यह पहले से ही नहीं है , सुरक्षित रूप से आवरण वस्तु को जारी करने के लिए कह सकते हैं; रैपर ऑब्जेक्ट को पता चल जाएगा कि उसने ऐसा किया है या अनुरोध को अंजाम दे सकता है या अनदेखा कर सकता है। तथ्य यह है कि जीसी गारंटी देता है कि आवरण के लिए एक संदर्भ हमेशा आवरण के लिए एक वैध संदर्भ होगा एक बहुत ही उपयोगी गारंटी है।
सुपरकट

43

अंतिम रूप

  • Finalizers हमेशा होना चाहिए protectedनहीं, publicया privateकि विधि आवेदन के कोड से सीधे नहीं कहा जा सकता तो और एक ही समय में, यह करने के लिए एक कॉल कर सकते base.Finalizeविधि
  • अंतिम रूप से अप्रबंधित संसाधनों को ही जारी करना चाहिए।
  • फ्रेमवर्क यह गारंटी नहीं देता है कि किसी भी उदाहरण पर एक अंतिम रूप से निष्पादन होगा।
  • कभी भी फाइनल में मेमोरी आवंटित न करें या फाइनल करने वालों से वर्चुअल तरीके न कहें।
  • तुल्यकालन से बचें और फाइनल में अपवादों को न उठाएं।
  • अंतिम रूप देने वालों का निष्पादन क्रम गैर-निर्धारक है - दूसरे शब्दों में, आप किसी अन्य वस्तु पर भरोसा नहीं कर सकते हैं जो अभी भी आपके अंतिम रूप में उपलब्ध है।
  • मूल्य प्रकारों पर अंतिम रूप निर्धारित न करें।
  • खाली विध्वंसक न बनाएं। दूसरे शब्दों में, आपको कभी भी एक विध्वंसक को स्पष्ट रूप से परिभाषित नहीं करना चाहिए जब तक कि आपकी कक्षा को अप्रबंधित संसाधनों को साफ करने की आवश्यकता नहीं है और यदि आप एक को परिभाषित करते हैं, तो उसे कुछ काम करना चाहिए। यदि, बाद में, आपको विध्वंसक में अप्रबंधित संसाधनों को साफ करने की आवश्यकता नहीं है, तो इसे पूरी तरह से हटा दें।

निपटान

  • IDisposableहर प्रकार पर लागू करें जिसमें एक अंतिम रूप है
  • सुनिश्चित करें कि Disposeविधि को कॉल करने के बाद किसी ऑब्जेक्ट को अनुपयोगी बना दिया जाता है । दूसरे शब्दों में, इस पर Disposeविधि को बुलाए जाने के बाद किसी वस्तु का उपयोग करने से बचें ।
  • एक बार जब आप उनके साथ कर रहे हैं, तो Disposeसभी IDisposableप्रकार पर कॉल करें
  • Disposeत्रुटियों को उठाए बिना कई बार कॉल करने की अनुमति दें ।
  • दमन बाद में Disposeविधि का उपयोग कर GC.SuppressFinalizeविधि के भीतर से अंतिम रूप में कहता है
  • डिस्पोजेबल मूल्य प्रकार बनाने से बचें
  • Disposeतरीकों के भीतर से अपवाद फेंकने से बचें

निपटान / अंतिम रूप दिया गया

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

17
मैंने हर जगह यही उत्तर पढ़ा और फिर भी मैं समझ नहीं पाया कि हर एक का उद्देश्य क्या है। मैं केवल नियमों के बाद नियम पढ़ता हूं, इससे ज्यादा कुछ नहीं।
इस्माइल

@ इस्माईल: और लेखक भी MSDN से कुछ पाठ को कॉपी और पेस्ट करने के अलावा कुछ नहीं जोड़ते हैं।
तारिक

@tarik मैंने पहले ही इसे सीखा है। मेरे पास "वादा" गर्भाधान था उस समय मैंने यह पूछा।
इस्माइल

31

जीसी द्वारा अंतिम रूप दिया जाता है जब यह ऑब्जेक्ट उपयोग में नहीं होता है।

निपटान सिर्फ एक सामान्य विधि है जिसे इस वर्ग का उपयोगकर्ता किसी भी संसाधन को जारी करने के लिए कह सकता है।

यदि उपयोगकर्ता डिसपोजल को कॉल करना भूल गया है और यदि क्लास ने अंतिम रूप से लागू किया है, तो जीसी यह सुनिश्चित कर देगा कि उसे कॉल किया जाता है।


3
अब तक का सबसे साफ उत्तर
दरोग्रिफ़ो

19

MCSD सर्टिफिकेशन टूलकिट (परीक्षा 70-483) पृष्ठ 193 से पुस्तक के बारे में कुछ कुंजियाँ हैं:

विध्वंसक dest (यह लगभग बराबर है)base.Finalize() , विध्वंसक को अंतिम विधि के ओवरराइड संस्करण में परिवर्तित किया जाता है जो विध्वंसक कोड को निष्पादित करता है और फिर बेस क्लास के फाइनल विधि को कॉल करता है। फिर इसकी पूरी तरह से गैर-नियतात्मक आप यह जानने में सक्षम नहीं हो सकते कि कब बुलाया जाएगा क्योंकि जीसी पर निर्भर करता है।

यदि किसी वर्ग में कोई प्रबंधित संसाधन नहीं हैं और कोई अप्रबंधित संसाधन नहीं हैं , तो इसे लागू नहीं करना चाहिए IDisposableया विनाशकारी नहीं होना चाहिए ।

यदि वर्ग में केवल संसाधन हैं , तो इसे लागू करना चाहिए, IDisposableलेकिन इसमें विध्वंसक नहीं होना चाहिए। (जब विध्वंसक निष्पादित होता है, तो आप सुनिश्चित नहीं कर सकते कि प्रबंधित ऑब्जेक्ट अभी भी मौजूद हैं, इसलिए आप उनके Dispose()तरीकों को वैसे भी कॉल नहीं कर सकते ।)

यदि कक्षा में केवल अप्रबंधित संसाधन हैं , तो इसे लागू करने की आवश्यकता होती है IDisposableऔर यदि प्रोग्राम कॉल नहीं करता है , तो इसे विध्वंसक की आवश्यकता होती है Dispose()

Dispose()विधि को एक से अधिक बार चलाने के लिए सुरक्षित होना चाहिए। आप इसे पहले चलाए जा चुके हैं या नहीं इसका ध्यान रखने के लिए एक चर का उपयोग करके प्राप्त कर सकते हैं।

Dispose()प्रबंधित और अप्रबंधित दोनों संसाधनों को मुक्त करना चाहिए

विध्वंसक को केवल मानव रहित संसाधनों को मुक्त करना चाहिए । जब विध्वंसक निष्पादित होता है, तो आप सुनिश्चित नहीं कर सकते कि प्रबंधित वस्तुएं अभी भी मौजूद हैं, इसलिए आप उनके निपटान के तरीकों को वैसे भी नहीं कह सकते। यह विहित protected void Dispose(bool disposing)पैटर्न का उपयोग करके प्राप्त किया जाता है , जहां केवल प्रबंधित संसाधनों को मुक्त किया जाता है (जब निपटाया जाता है) disposing == true

संसाधनों को मुक्त करने के बाद, Dispose()कॉल करना चाहिएGC.SuppressFinalize , इसलिए ऑब्जेक्ट अंतिम रूप कतार को छोड़ सकता है।

मानव रहित और प्रबंधित संसाधनों वाले वर्ग के लिए कार्यान्वयन का एक उदाहरण:

using System;

class DisposableClass : IDisposable
{
    // A name to keep track of the object.
    public string Name = "";

    // Free managed and unmanaged resources.
    public void Dispose()
    {
        FreeResources(true);

        // We don't need the destructor because
        // our resources are already freed.
        GC.SuppressFinalize(this);
    }

    // Destructor to clean up unmanaged resources
    // but not managed resources.
    ~DisposableClass()
    {
        FreeResources(false);
    }

    // Keep track if whether resources are already freed.
    private bool ResourcesAreFreed = false;

    // Free resources.
    private void FreeResources(bool freeManagedResources)
    {
        Console.WriteLine(Name + ": FreeResources");
        if (!ResourcesAreFreed)
        {
            // Dispose of managed resources if appropriate.
            if (freeManagedResources)
            {
                // Dispose of managed resources here.
                Console.WriteLine(Name + ": Dispose of managed resources");
            }

            // Dispose of unmanaged resources here.
            Console.WriteLine(Name + ": Dispose of unmanaged resources");

            // Remember that we have disposed of resources.
            ResourcesAreFreed = true;
        }
    }
}

2
यह एक अच्छा जवाब है! लेकिन मुझे लगता है कि यह गलत है: "विध्वंसक को GC.SuppressFinalize को कॉल करना चाहिए"। इसके बजाय, सार्वजनिक विवाद () विधि GC.SuppressFinalize को कॉल नहीं करना चाहिए? देखें: docs.microsoft.com/en-us/dotnet/api/… इस विधि को कॉल करने से कचरा संग्रहकर्ता को Object.Finalize (जो विध्वंसक द्वारा ओवरराइड होता है) को कॉल करने से रोकता है।
ईवा

7

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

कचरा संग्रह के विषय के बारे में जानने के लिए बहुत कुछ है , लेकिन यह एक शुरुआत है।


5
तुम कहाँ: मैं यकीन है कि सी # आवेदनों की तुलना में अधिक 1% डेटाबेस का उपयोग कर रहा हूँ है IDisposable एसक्यूएल सामान के बारे में चिंता करने के लिए।
सैमुअल

1
इसके अलावा, यदि आप IDisposables एनकैप्सुलेट करते हैं, तो आपको आईडीसिसोपयोगी लागू करना चाहिए। जो शायद अन्य 1% को कवर करता है।
डैरेन क्लार्क

@ सैमुअल: मैं यह नहीं देखता कि डेटाबेस का इससे क्या लेना-देना है। यदि आप कनेक्शन बंद करने के बारे में बात कर रहे हैं, तो यह ठीक है, लेकिन यह एक अलग मामला है। आपको समय पर ढंग से कनेक्शन बंद करने के लिए ऑब्जेक्ट को डिस्पोज़ नहीं करना है।
जेपी अलीटो

1
@JP: लेकिन द यूज़िंग (...) पैटर्न इसे सामना करने के लिए बहुत सरल बनाता है।
ब्रूडी

2
सहमत हैं, लेकिन यह बिल्कुल बात है। का उपयोग कर पैटर्न आप के लिए कॉल को छुपाता है।
जेपी अलीटो

6

फ़ाइनलीज़र निहित सफाई के लिए है - आपको इसका उपयोग तब करना चाहिए जब कोई वर्ग संसाधनों का प्रबंधन करता है जिसे बिल्कुल साफ किया जाना चाहिए अन्यथा आप हैंडल / मेमोरी आदि को लीक कर देंगे ...

सही ढंग से एक अंतिम रूप से लागू करना बहुत मुश्किल है और जहाँ भी संभव हो SafeHandleउससे बचा जाना चाहिए - वर्ग (avaialble in .Net v2.0 और इसके बाद के संस्करण) का मतलब है कि अब आप शायद ही कभी (यदि कभी भी) को अंतिम रूप से लागू करने की आवश्यकता है।

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

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

डीजी अपडेट देखें : मैं जो भी अंतिम और सलाहकारों पर सिफारिशों का सबसे अच्छा और सबसे पूरा सेट मानता हूं, उसके लिए निपटान, अंतिमकरण, और संसाधन प्रबंधनIDisposable


3

सारांश है -

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

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

एक ऐसे वर्ग के लिए जो अप्रबंधित संसाधनों का उपयोग करता है, सबसे अच्छा अभ्यास दोनों को परिभाषित करना है - डिस्पोज़ () विधि और फ़ाइनलीज़र - का उपयोग उस स्थिति में किया जाता है जब कोई डेवलपर ऑब्जेक्ट को हटाने के लिए भूल जाता है। दोनों प्रबंधित और अप्रबंधित संसाधनों को साफ करने के लिए एक साझा विधि का उपयोग कर सकते हैं: -

class ClassWithDisposeAndFinalize : IDisposable
{
    // Used to determine if Dispose() has already been called, so that the finalizer
    // knows if it needs to clean up unmanaged resources.
     private bool disposed = false;

     public void Dispose()
     {
       // Call our shared helper method.
       // Specifying "true" signifies that the object user triggered the cleanup.
          CleanUp(true);

       // Now suppress finalization to make sure that the Finalize method 
       // doesn't attempt to clean up unmanaged resources.
          GC.SuppressFinalize(this);
     }
     private void CleanUp(bool disposing)
     {
        // Be sure we have not already been disposed!
        if (!this.disposed)
        {
             // If disposing equals true i.e. if disposed explicitly, dispose all 
             // managed resources.
            if (disposing)
            {
             // Dispose managed resources.
            }
             // Clean up unmanaged resources here.
        }
        disposed = true;
      }

      // the below is called the destructor or Finalizer
     ~ClassWithDisposeAndFinalize()
     {
        // Call our shared helper method.
        // Specifying "false" signifies that the GC triggered the cleanup.
        CleanUp(false);
     }

2

सबसे अच्छा उदाहरण जो मुझे पता है।

 public abstract class DisposableType: IDisposable
  {
    bool disposed = false;

    ~DisposableType()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(false);
      }
    }

    public void Dispose()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(true);
        GC.SuppressFinalize(this);
      }
    }

    public void Close()
    {
      Dispose();
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposing) 
      {
        // managed objects
      }
      // unmanaged objects and resources
    }
  }

2

C # में अंतिम रूप और निपटान के तरीकों के बीच का अंतर।

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

डिस्पोज़ मेथड: कोड से कॉल करने पर हमारा उस पर निम्न स्तर का नियंत्रण होता है। जब भी हमें लगता है कि यह प्रयोग करने योग्य नहीं है, तो हम अप्रबंधित संसाधनों को पुनः प्राप्त कर सकते हैं। हम इसे आईडीसपोजिशन पैटर्न लागू करके प्राप्त कर सकते हैं।


1

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

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


1

Dispose और Finalize के बीच मुख्य अंतर यह है कि:

Disposeआमतौर पर आपके कोड द्वारा बुलाया जाता है। जब आप इसे कहते हैं तो संसाधन तुरंत मुक्त हो जाते हैं। लोग विधि को कॉल करना भूल जाते हैं, इसलिए using() {}कथन का आविष्कार किया जाता है। जब आपका प्रोग्राम अंदर कोड का निष्पादन समाप्त कर देता है {}, तो यह Disposeस्वचालित रूप से कॉल विधि होगी ।

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

मैं व्यक्तिगत रूप से डिस्पोज़ में अधिकांश विनाश तर्क लिखूंगा। उम्मीद है, यह भ्रम को साफ करता है।


-1

जैसा कि हम जानते हैं कि निपटाने और अंतिम रूप देने के लिए दोनों का उपयोग अप्रबंधित संसाधनों को मुक्त करने के लिए किया जाता है .. लेकिन अंतर को अंतिम रूप दिया जाता है दो संसाधनों का उपयोग करने के लिए, जहां निपटान एक चक्र का उपयोग करता है।


निपटान संसाधन को तुरंत मुक्त करता है । किसी भी समयबद्धता के साथ संसाधन को अंतिम रूप दे सकते हैं या मुक्त नहीं कर सकते हैं।
सुपरकैट

1
आह, उसका मतलब यह है कि "जीसी द्वारा इसकी मेमोरी दोबारा प्राप्त होने से पहले इसे दो बार पहचाने जाने योग्य वस्तु की जरूरत है", यहाँ और अधिक पढ़ें: ericlippert.com/2015/05/18/…
एरोसॉन

-4

पहले भाग पर जवाब देने के लिए आपको ऐसे उदाहरण उपलब्ध कराने चाहिए जहाँ लोग एक ही कक्षा-वस्तु के लिए अलग-अलग दृष्टिकोण का उपयोग करते हैं। अन्यथा जवाब देना मुश्किल (या अजीब भी) है।

दूसरे प्रश्न के रूप में बेहतर पढ़ने के लिए सबसे पहले आइडीसोपायरी इंटरफ़ेस का यह उचित उपयोग करें जो दावा करता है कि

यह तुम्हारी पसंद है! लेकिन डिस्पोजल चुनें।

दूसरे शब्दों में: जीसी केवल फाइनलिज़र के बारे में जानता है (यदि कोई हो। इसे माइक्रोसॉफ्ट के विनाशकर्ता के रूप में भी जाना जाता है)। एक अच्छा कोड दोनों (फाइनल और डिस्पोज़) से सफाई का प्रयास करेगा।

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