2010-03-22 9 views
21

लागू करता है मेरे पास एक अभिभावक और बाल वर्ग है जिसे दोनों को IDisposable लागू करने की आवश्यकता है। virtual (और base.Dispose()) कहां से खेलना चाहिए? जब मैं Dispose(bool disposing) कॉल को ओवरराइड करता हूं, तो यह वास्तव में अजीब लगता है कि मैं IDisposable को स्पष्ट Dispose() फ़ंक्शन (केवल विरासत में उपयोग करने वाले) के बिना लागू करता हूं, लेकिन बाकी सब कुछ।उप-वर्ग पर आईडीस्पोजेबल लागू करना जब माता-पिता IDISposable

मैं (काफ़ी trivialized) क्या कर रहा था:

internal class FooBase : IDisposable 
{ 
    Socket baseSocket; 

    private void SendNormalShutdown() { } 

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

    private bool _disposed = false; 
    protected virtual void Dispose(bool disposing) 
    { 
     if (!_disposed) 
     { 
      if (disposing) 
      { 
       SendNormalShutdown(); 
      } 
      baseSocket.Close(); 
     } 
    } 

    ~FooBase() 
    { 
     Dispose(false); 
    } 
} 

internal class Foo : FooBase, IDisposable 
{ 
    Socket extraSocket; 

    private bool _disposed = false; 
    protected override void Dispose(bool disposing) 
    { 
     if (!_disposed) 
     { 
      extraSocket.Close(); 
     } 
     base.Dispose(disposing); 
    } 

    ~Foo() 
    { 
     Dispose(false); 
    } 

} 
+0

[MSDN] (https://msdn.microsoft.com/en-us/library/system.idisposable (v = vs.110) .aspx0) कैसे IDisposable को लागू करने वस्तुओं उपवर्ग के लिए पर सलाह नहीं है । – PeterM

उत्तर

23

जब मैं सिर्फ निपटान (bool निपटान) कॉल ओवरराइड, यह एक स्पष्ट निपटान बिना वास्तव में अजीब करते हुए कहा कि मैं IDisposable लागू लगता है() कार्य (विरासत में से एक का उपयोग), लेकिन बाकी सब कुछ है।

यह ऐसा कुछ है जिसके बारे में आपको चिंता नहीं करना चाहिए।

जब आप एक आईडीस्पोज़ेबल क्लास को उप-वर्गीकृत करते हैं, तो बेस क्लास द्वारा "डिस्प्ले पैटर्न" प्लंबिंग के सभी पहले से ही आपके लिए संभाला जा रहा है। आप वास्तव में कुछ नहीं करना है लेकिन protected Dispose(bool) विधि ओवरराइड, और ट्रैक है कि क्या आप निपटारा किया गया है पहले से ही (ठीक से ObjectDisposedException बढ़ाने के लिए।)

जानकारी के लिए, Subclassing from an IDisposable class पर अपने ब्लॉग पोस्ट देखें।


इसके अलावा, अक्सर, यह एक अच्छा विचार IDisposable वर्ग encapsulating के बजाय इसे उपवर्गीकरण विचार करने के लिए है। ऐसे समय होते हैं जब एक आईडीस्पोजेबल वर्ग उप-वर्गीकरण उचित होता है, लेकिन वे कुछ दुर्लभ होते हैं। Encapsulation अक्सर एक बेहतर विकल्प है।

+0

आह, मुझे लगता है कि मेरी चिंताएं निराधार थीं और मैं इसे सही करने के करीब था (मुझे आश्चर्य है कि मैंने फाइनलाइज़र को फिर से कार्यान्वित करने के विचार को उठाया ... ओह ठीक है)। और हाँ, सामान्य रूप से विरासत कुछ ऐसा है जो मुझे कम और कम उपयोग करके मिलती है। – Tanzelax

+0

रीड आपका ब्लॉग शानदार है ... लेकिन यहां अपने उत्तर की गिनती पर ध्यान दें - 7 (1 मेरा है:)) .... लोग इसे पर्याप्त रूप से कम नहीं कर सकते .. शर्म की बात है। –

3

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

+1

मुझे लगता है कि मैं केवल स्पष्ट ': आईडीस्पोजेबल' ले सकता हूं, क्योंकि यह पहले से ही उस इंटरफेस को विरासत में ले रहा है। मुझे लगता है कि मैं स्पष्ट रूप से यह कहता हूं कि "इस वर्ग में कुछ विशेष निपटान है जो होता है"। वैसे, इनपुट के लिए धन्यवाद। :) – Tanzelax

1

बच्चे वर्ग को आभासी निपटान को ओवरराइड करना चाहिए, सबक्लास के लिए विशिष्ट डिस्पोजेक्ट करना चाहिए, और सुपरक्लास 'निपटान करें, जो बदले में अपना काम करेगा।

संपादित करें: http://davybrion.com/blog/2008/06/disposing-of-the-idisposable-implementation/ मैं इस तरह के मामलों में पैटर्न का पालन करता हूं। विशेष रूप से 'डिस्पोजेबल' वर्ग नहीं, बल्कि विरासत और ओवरराइड।

+0

मुझे यकीन नहीं है कि मुझे पहले से-फूले हुए आईडीस्पोजेबल पैटर्न में और भी वर्चुअल/अमूर्त विधियों को जोड़ने का विचार पसंद है ... – Tanzelax

+0

@Tanzelax प्रत्येक के लिए, मुझे लगता है। प्रदान किया गया कोड मेरे लिए उपयोगी रहा है जहां मेरे पास कक्षाओं का पदानुक्रम है जिसे डिस्पोजेबल होने की आवश्यकता है। अधिकांश सेटअप शीर्ष-स्तरीय वर्ग में है, और प्रति सबक्लास के लिए न्यूनतम अतिरिक्त कोड की आवश्यकता होती है। –

3

जब आपको आवश्यकता नहीं होती है तो जटिल चीजें क्यों जटिल होती हैं?

चूंकि आप किसी भी अप्रबंधित संसाधनों को समाहित नहीं करते हैं, इसलिए आपको अंतिम रूप देने के बारे में सभी की आवश्यकता नहीं है। और, आपकी कक्षाएं आंतरिक हैं, जो बताती हैं कि आप अपनी खुद की असेंबली के भीतर विरासत पदानुक्रम को नियंत्रित करते हैं।

तो, straighforward दृष्टिकोण होगा:

internal class FooBase : IDisposable 
{ 
    Socket baseSocket; 

    private void SendNormalShutdown() 
    { 
    // ... 
    } 

    private bool _disposed = false; 

    public virtual void Dispose() 
    { 
    if (!_disposed) 
    { 
     SendNormalShutdown(); 
     baseSocket.Close(); 
     _disposed = true; 
    } 
    } 
} 

internal class Foo : FooBase 
{ 
    Socket extraSocket; 

    private bool _disposed = false; 

    public override void Dispose() 
    { 
    if (!_disposed) 
    { 
     extraSocket.Close(); 
     _disposed = true; 
    } 

    base.Dispose(); 
    } 
} 

यहां तक ​​कि जब आप अप्रबंधित संसाधनों की क्या ज़रूरत है, मैं कहेंगे आप ज्यादा अपने स्वयं के डिस्पोजेबल कक्षा में encapsulating them से बेहतर कर रहे हैं और जैसे आप चाहते उन्हें प्रयोग किसी अन्य डिस्पोजेबल का उपयोग करें; उपरोक्त कोड के रूप में straighforward के रूप में।

+1

क्या आप किसी ऐसे मामले के बारे में सोच सकते हैं जहां एक उप-वर्ग के पास क्लीनअप फ़ाइनलाइज़र होना चाहिए जब कोई अभिभावक वर्ग नहीं (ऑब्जेक्ट से विरासत के छोटे मामले से अलग)? मैं एक फाइनलर जोड़ना समझ सकता हूं जिसका काम अनुचित रूप से त्याग किए गए ऑब्जेक्ट्स की शिकायत करना है, लेकिन आईएमएचओ को सफाई की आवश्यकता वाले किसी भी चीज को अपनी अंतिम श्रेणी में होना चाहिए; मैं * नहीं * अपवादों के बारे में सोच सकता हूं। – supercat

+0

@supercat: मैं पूरी तरह से [सहमत] (http://codecrafter.blogspot.com/2010/01/revisiting-idisposable.html)। –

0

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

http://joeduffyblog.com/2005/04/08/dg-update-dispose-finalization-and-resource-management/

पहले बात को याद है कि एक finalizer समय के सबसे अधिक जरूरत नहीं है है। यह अप्रबंधित संसाधनों को साफ़ करने के लिए है जहां आप सीधे मूल संसाधन धारण कर रहे हैं, यानी केवल वे संसाधन जिनके पास अपना स्वयं का फ़ाइनलाइज़र नहीं है।

यहां बेस-क्लास सबक्लास जोड़ी के लिए एक उदाहरण दिया गया है।

// Base class 

    #region IDisposable Members 

    private bool _isDisposed; 

    public void Dispose() 
    { 
     this.Dispose(true); 
     // GC.SuppressFinalize(this); // Call after Dispose; only use if there is a finalizer. 
    } 

    protected virtual void Dispose(bool isDisposing) 
    { 
     if (!_isDisposed) 
     { 
      if (isDisposing) 
      { 
       // Clear down managed resources. 

       if (this.Database != null) 
        this.Database.Dispose(); 
      } 

      _isDisposed = true; 
     } 
    } 

    #endregion 


// Subclass 

    #region IDisposable Members 

    private bool _isDisposed; 

    protected override void Dispose(bool isDisposing) 
    { 
     if (!_isDisposed) 
     { 
      if (isDisposing) 
      { 
       // Clear down managed resources. 

       if (this.Resource != null) 
        this.Resource.Dispose(); 
      } 

      _isDisposed = true; 
     } 

     base.Dispose(isDisposing); 
    } 

    #endregion 

ध्यान दें कि उपclass का अपना _is डिसोस्ड सदस्य है। संसाधनों पर नल-जांच भी ध्यान दें क्योंकि आप इन ब्लॉकों में कोई अपवाद नहीं चाहते हैं।

ल्यूक

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