2010-04-09 18 views
19

मेरे पास कुछ प्रश्न हैं जिसके लिए मुझे उचित उत्तर नहीं मिल रहा है।जब हमें कोई विनाशक नहीं है तो हम SuppressFinalize को क्यों कॉल कर सकते हैं

1) जब हम विनाशक नहीं होते हैं तो हम निपटान समारोह में SuppressFinalize क्यों कॉल कर सकते हैं।

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

नीचे दिए गए कोड को मैंने नेट से कॉपी किया है।

class Test : IDisposable 
    { 
    private bool isDisposed = false; 

    ~Test() 
    { 
     Dispose(false); 
    } 

    protected void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
     // Code to dispose the managed resources of the class 
     } 
     // Code to dispose the un-managed resources of the class 

     isDisposed = true; 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 
    } 

क्या होगा अगर मैं बूलियन संरक्षित कार्य को हटा दें और नीचे के रूप में लागू करें।

class Test : IDisposable 
    { 
    private bool isDisposed = false; 

    ~Test() 
    { 
     Dispose(); 
    } 


    public void Dispose() 
    { 
     // Code to dispose the managed resources of the class 
     // Code to dispose the un-managed resources of the class 
     isDisposed = true; 

     // Call this since we have a destructor . what if , if we don't have one 
     GC.SuppressFinalize(this); 
    } 
    }  

उत्तर

17

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

तुम सिर्फ कुछ और जो IDisposable लागू करता है के लिए एक संदर्भ रोक रखी है, तो आप लगभग निश्चित रूप से एक finalizer जरूरत नहीं है। आप कुछ इस तरह के साथ क्या कर सकते हैं:

public sealed class Foo : IDisposable 
{ 
    private bool disposed; 
    private FileStream stream; 

    // Other code 

    public void Dispose() 
    { 
     if (disposed) 
     { 
      return; 
     } 
     stream.Dispose(); 
     disposed = true; 
    } 
} 

ध्यान दें कि यह धागा सुरक्षित नहीं है, लेकिन यह शायद एक समस्या नहीं होगी।

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

यदि आप अनियंत्रित विरासत की अनुमति देने की आवश्यकता है (यानी आप शर्त लगा सकते हैं कि उप-वर्गों की विशेष आवश्यकताएं होंगी) तो आपको पूर्ण पैटर्न के लिए जाना होगा।

ध्यान दें कि SafeHandle .NET 2.0 से, यह भी दुर्लभ है कि आपको .NET 1.1 में अपने स्वयं के फ़ाइनलाइज़र की आवश्यकता है।


क्यों पहली जगह में एक disposing ध्वज के बारे में अपनी बात को संबोधित करने के लिए: यदि आप एक finalizer भीतर चला रहे हैं, अन्य वस्तुओं आप पहले से ही अंतिम रूप दे दिया गया हो सकता है का संदर्भ लें। आप उन्हें खुद को साफ करना चाहिए, और आप केवल संसाधनों आप सीधेखुद को साफ करना चाहिए।

+0

हाय जॉन, बस नाइटपिकिंग, लेकिन "जो कुछ भी संसाधन धारण करता है वह सीधे उससे निपट सकता है", शायद उस बिंदु पर जोर देने के लिए "इससे निपटने" के लिए "(यानी" कर सकते हैं "->" होगा ") होना चाहिए यह बाहरी वर्ग की नौकरी बिल्कुल संभालने के लिए नहीं है। –

+0

एक और सवाल, सिस्टम के बाद से। ऑब्जेक्ट सभी ऑब्जेक्ट्स का आधार है, जो डिफ़ॉल्ट रूप से एक अंतिम विधि लागू होती है, भले ही हमने विनाशक प्रदान नहीं किया है, जीसी ने इसे अंतिम कतार में नहीं रखा है? या हम क्यों कहते हैं कि यदि हम एक विनाशकारी वस्तु प्रदान नहीं करते हैं तो अंतिम कतार में नहीं रखा जाएगा? क्योंकि विरासत संरक्षित सदस्यों के आधार पर व्युत्पन्न वर्ग के निजी सदस्यों की तरह हैं। – somaraj

+0

क्या गैर-तुच्छ माता-पिता वर्ग से प्राप्त उप-वर्ग के लिए कोई वैध कारण है यदि क्लीनर फ़ाइनलज़र है तो माता-पिता नहीं करते हैं? मैं किसी भी मामले के बारे में नहीं सोच सकता जहां व्युत्पन्न वर्ग के लिए किसी भी अप्रबंधित संसाधनों को अपनी कक्षा में शामिल करने के लिए बेहतर नहीं होगा, इसके अपने अंतिम फाइनलर को पूरी तरह से मुख्य से अलग किया जाएगा। असल में, यहां तक ​​कि अगर कोई चाहता है कि "अलार्म घंटी" फाइनलाइज़र है, तो व्युत्पन्न कक्षा में फाइनलाइज़र जोड़ने के बजाय, * * को अपनी कक्षा में शामिल करना बेहतर हो सकता है। – supercat

5

पहला संस्करण रखें, यह सुरक्षित है और निपटान पैटर्न का सही कार्यान्वयन है।

  1. SuppressFinalize कॉलिंग जीसी है कि आप (अपने वर्ग द्वारा आयोजित संसाधनों का) सभी विनाश किया है/अपने आप को निपटाने और यह नाशक कॉल करने की आवश्यकता नहीं है कि बताता है।

  2. यदि आपकी कक्षा का उपयोग करने वाले कोड में पहले से ही निपटान किया गया है, तो आपको परीक्षण की आवश्यकता है और आपको जीसी को फिर से निपटाने के लिए नहीं बताना चाहिए।

this एमएसडीएन दस्तावेज़ देखें (विधियों को निपटाना चाहिए SuppressFinalize)।

+0

हाँ मुझे समझ नहीं है कि SupressFinalze अंतिम रूप को कॉल करने से जी सी नहीं कर पाएगा। लेकिन मेरा संदेह यह है कि जब मेरे पास विनाशकारी नहीं है तो हमें SupressFinalze को कॉल करने की आवश्यकता क्यों है। क्योंकि अंतिमकरण कतार में उन objets के लिए अंतिम रूप से बुलाया जाएगा और मेरे ऑब्जेक्ट में विनाशक नहीं है इसलिए जीसी कॉल करने वाला नहीं है। 2) मेरा दूसरा पिंट है, क्यों पट्टियों का निपटान एक ओवरलोडेड निपटान मस्ती के बारे में जोर देते हैं जो एक बुलियन लेता है। जो प्रबंधित या अप्रबंधित संसाधनों की रिहाई को नियंत्रित करेगा। जब ऑब्जेक्ट का निपटारा किया जा रहा है, तो हमें संसाधनों को अलग-अलग इलाज करने की आवश्यकता क्यों है, सभी को मुक्त करने दें। – somaraj

+2

वह नियम केवल तभी प्रासंगिक होता है जब आपको अंतिमकर्ता की आवश्यकता होती है या आपको उप-वर्गों को अंतिम करने की अनुमति देने की आवश्यकता होती है। कई स्थितियों में यह मामला नहीं है। –

+5

@ सोमाराज: बिंदु यह है कि * आपके * वर्ग में फाइनलाइज़र नहीं हो सकता है, लेकिन एक * सबक्लास * हो सकता है। –

3

यहां मुख्य तथ्यों

1) Object.Finalize क्या अपनी कक्षा ओवरराइड जब यह एक finalizer है कर रहे हैं। ~ TypeName() विनाशक विधि 'ओवरराइड फ़ाइनलाइज()' आदि के लिए सिर्फ शॉर्टेंड है

2) आप जीसी.SuppressFinalize को कॉल करते हैं यदि आप अंतिम रूप से पहले अपने निपटान विधि में संसाधनों का निपटान कर रहे हैं (यानी जब किसी उपयोग ब्लॉक से बाहर आते हैं आदि)। यदि आपके पास फाइनेंजर नहीं है, तो आपको ऐसा करने की आवश्यकता नहीं है। यदि आप एक finalizer है, तो यह है कि वस्तु को अंतिम रूप कतार के हटा लेने के (इतनी के रूप में finalizer आमतौर पर निपटान प्रणाली को बुलाती है और साथ ही हम दो बार सामान के निपटान न)

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

4) अंतिमकर्ता महंगे होते हैं जिनके पास अंतिम उत्पादक जनरेशन -0 संग्रह (सबसे कुशल) में कचरा नहीं हो सकता है, और उन्हें एफ-रीच करने योग्य पर संदर्भ के साथ जनरेशन -1 में पदोन्नत किया जाता है। कतार, ताकि वे एक जीसी रूट का प्रतिनिधित्व करते हैं। यह जब तक जीसी एक पीढ़ी -1 संग्रह है कि finalizer कहा जाता हो जाता है करता नहीं है, और संसाधनों जारी कर रहे हैं - तो finalizers लागू केवल जब बहुत महत्वपूर्ण है - और यह सुनिश्चित करें कि वस्तुओं को अंतिम रूप की आवश्यकता है कि संभव के रूप में छोटे कर रहे हैं - क्योंकि सभी वस्तुओं है कि कर सकते हैं आपके अंतिम वस्तु द्वारा पहुंचाया जा सकता है जनरेशन -1 को भी बढ़ावा दिया जाएगा।

2

1. पहला सवाल

मूल रूप से के लिए जवाब है, तो आप SuppressFinalize विधि कॉल करने के अगर अपनी कक्षा एक को अंतिम रूप देने विधि (नाशक) नहीं है नहीं है। मेरा मानना ​​है कि लोगों को ज्ञान की कमी के कारण कोई अंतिम विधि नहीं होने पर भी SupressFinalize कहते हैं। दूसरा सवाल

अंतिम रूप विधि का उद्देश्य के लिए

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

1

तुम हमेशा SuppressFinalize() क्योंकि आप हो सकता है (या भविष्य में है) एक व्युत्पन्न वर्ग है कि एक finalizer लागू करता है फोन करना चाहिए।

मान लीजिए कि आप एक आधार वर्ग है कि एक finalizer नहीं है करते हैं - और आप SuppressFinalize कॉल करने के लिए नहीं() का फैसला किया।फिर 3 महीने बाद आप एक व्युत्पन्न कक्षा जोड़ते हैं जो एक फाइनलाइज़र जोड़ता है। यह संभावना है कि आप बेस क्लास तक जाकर भूल जाएंगे और SuppressFinalize() पर कॉल जोड़ देंगे। यदि कोई फाइनलाइज़र नहीं है तो इसे कॉल करने में कोई हानि नहीं है।

मेरे सुझाव IDisposable पैटर्न यहां पोस्ट है: How to properly implement the Dispose Pattern

संबंधित मुद्दे

 संबंधित मुद्दे