2009-11-09 16 views
7

मैं एक अमूर्त वर्ग IDisposable को लागू करता है, तो तरह है निम्नलिखित: सी # सार निपटान विधि

Microsoft.Design

: ('इस' या 'मेरे' विजुअल बेसिक में 'ConnectionAccessor.Dispose()' संशोधित करें ताकि वह निपटान (सही) कहता है, तो मौजूदा वस्तु दृष्टान्त पर GC.SuppressFinalize कॉल), और फिर लौटता है।

यह सिर्फ मूर्ख जा रहा है, मुझे बता एक सार विधि के शरीर को संशोधित करने, या मैं Dispose के किसी भी व्युत्पन्न उदाहरण में आगे कुछ करना चाहिए है?

+0

आपको अपने इंटरफ़ेस में निपटान() जोड़ने की आवश्यकता क्यों है? यदि इसे IDISposable से विरासत में मिला है तो निपटान() विधि पहले से ही आपके इंटरफ़ेस का हिस्सा है। –

+0

सेठ, आपको सभी इंटरफेस सदस्यों को लागू करना होगा। इसे छोड़ना संकलित नहीं होगा। पैटर्न का उल्लेख करने के लिए –

उत्तर

12

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

public class Base 
{ 
    ~Base() 
    { 
     Dispose(false); 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); // so that Dispose(false) isn't called later 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      // Dispose all owned managed objects 
     } 

     // Release unmanaged resources 
    } 
} 

कुंजी यहाँ अप्रबंधित सफाई के लिए finalizer और Dispose के बीच कोई दोहराव नहीं है, और अभी तक किसी भी व्युत्पन्न वर्ग दोनों प्रबंधित और अप्रबंधित सफाई का विस्तार कर सकते हैं।

protected abstract void Dispose(bool disposing) 

और बाकी सब कुछ छोड़ के रूप में:

अपने मामले के लिए, आप क्या करना चाहिए यह है। यहां तक ​​कि यह संदिग्ध मूल्य है, क्योंकि आप अब अपने व्युत्पन्न वर्गों को Dispose लागू करने के लिए लागू कर रहे हैं - और आप कैसे जानते हैं कि उन सभी को इसकी आवश्यकता है? यदि आपकी बेस क्लास का निपटान करने के लिए कुछ भी नहीं है, लेकिन अधिकतर व्युत्पन्न कक्षाएं संभवतः (कुछ अपवादों के साथ) कर सकती हैं, तो बस खाली कार्यान्वयन प्रदान करें। यह System.IO.Stream (स्वयं सार) है, इसलिए उदाहरण है।

+0

मुझे बहुत कुछ लोगों को ऐसा करने की सलाह दी गई थी: http://nitoprograms.blogspot.com/2009/08/how-to-implement-idisposable-and.html - पैटर्न बहुत आसान होगा यदि पैटर्न बहुत आसान हो इसमें कक्षाओं के लिए अंतर्निहित समर्थन नहीं था जो प्रबंधित और अप्रबंधित संसाधनों को मिलाते थे। –

+0

यदि किसी विशेष वर्ग से प्राप्त किसी भी वर्ग को आईडीस्पोजेबल को लागू करने की आवश्यकता होगी, और यदि कोई ऑब्जेक्ट जो बेस-क्लास प्रकार दिया जाता है, तो उसे अंतिम उपयोगी संदर्भ प्राप्त हो सकता है, बेस क्लास को IDISposable लागू करना चाहिए, भले ही व्युत्पन्न कक्षाओं के विशाल बहुमत की आवश्यकता नहीं होगी। – supercat

+0

क्या यह पैटर्न .net 2 के बाद पुराना नहीं है? मेरी समझ यह है कि अप्रबंधित संसाधन कुछ प्रकार के सुरक्षित हैंडल/महत्वपूर्ण हैंडल द्वारा आयोजित किए जाने चाहिए और सामान्य उपयोगकर्ता लागू कक्षाओं को अब अंतिम रूप देने की आवश्यकता नहीं है। और उनके 'निपटान' को हैंडल पर बस 'निपटान' कहते हैं। – CodesInChaos

10

चेतावनी मूल रूप से आपको अपनी कक्षा में Dispose pattern लागू करने के लिए कहती है।

जिसके परिणामस्वरूप कोड इस तरह दिखना चाहिए:

public abstract class ConnectionAccessor : IDisposable 
{ 
    ~ConnectionAccessor() 
    { 
     Dispose(false); 
    } 

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

    protected virtual void Dispose(bool disposing) 
    { 
    } 
} 
+3

+1, और यह इंगित करते हुए कि निपटान (बूल) आभासी/अमूर्त विधि होनी चाहिए जो व्युत्पन्न कक्षाओं को लागू या ओवरराइड करना चाहिए, निपटान नहीं()। – Yoopergeek

-1

हालांकि चेतावनी दिलचस्प है। सी # डिजाइनरों में से एक एरिक लिपर्ट, इस बारे में ब्लॉग किया गया कि क्यों त्रुटि संदेश होना चाहिए "नैदानिक ​​लेकिन अनुशासनात्मक नहीं: समस्या का वर्णन करें, समाधान नहीं"। Read here.

+1

यह एक कंपाइलर त्रुटि संदेश नहीं है। यह एक उपकरण चलाने का नतीजा है जो विशेष रूप से समस्याग्रस्त चीजों को इंगित करता है। समाधान को इंगित करने में कुछ भी गलत नहीं है। –

+0

निश्चित रूप से। बस लिंक साझा करना चाहता था। यह मेरे पास आया क्योंकि संदेश समस्या नहीं बताता है लेकिन केवल समाधान देता है। उम्मीद है कि ऐसा करने वाला एक पिछला संदेश था। –

+0

यह मूल प्रश्न के लिए टेंगेंशियल है। –

1

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

मैं निपटाने पैटर्न ब्रूस Wagners पुस्तक Effective C# में उल्लेख किया है जो मूल रूप से है का उपयोग करें:

public class BaseClass : IDisposable 
{ 
    private bool _disposed = false; 
    ~BaseClass() 
    { 
     Dispose(false); 
    } 

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

    protected virtual void Dispose(bool disposing) 
    { 
     if (_disposed) 
      return; 

     if (disposing) 
     { 
      //release managed resources 
     } 

     //release unmanaged resources 

     _disposed = true; 
    } 
} 

public void Derived : BaseClass 
{ 
    private bool _disposed = false; 

    protected override void Dispose(bool disposing) 
    { 
     if (_disposed) 
      return; 

     if (disposing) 
     { 
      //release managed resources 
     } 

     //release unmanaged resources 

     base.Dispose(disposing); 
     _disposed = true; 
    } 
3

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

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

+0

मेरी पसंदीदा पकड़। ज्यादातर लोग इसे समझने की कोशिश करने से परेशान नहीं हैं, और उन्हें सबसे अच्छी सलाह है कि वे केवल माइक्रोसॉफ्ट पैटर्न को लागू करें। यहां "आधिकारिक" पैटर्न की तुलना में मुझे लगता है कि यह बहुत बेहतर सलाह है: http://nitoprograms.blogspot.com/2009/08/how-to-implement-idisposable-and.html –

+0

यह वास्तव में एक अच्छा ब्लॉग पोस्ट है विषय - सरल और भी बिंदु। –