2009-09-13 13 views
20

पर IDISposable लागू करना मुझे नहीं लगता कि इस सवाल से पहले पूछा गया है। मैं एक सीलबंद वर्ग पर IDisposable को लागू करने के सर्वोत्तम तरीके से थोड़ा उलझन में हूं- विशेष रूप से, एक सीलबंद वर्ग जो बेस क्लास से प्राप्त नहीं होता है। (यानी, एक "शुद्ध मुहरबंद वर्ग" जो मेरा बना हुआ शब्द है।)एक सीलबंद कक्षा

शायद आप में से कुछ मेरे साथ सहमत हैं कि IDisposable लागू करने के लिए दिशानिर्देश बहुत भ्रमित हैं। उस ने कहा, मैं जानना चाहता हूं कि जिस तरह से मैं IDisposable को लागू करना चाहता हूं वह पर्याप्त और सुरक्षित है।

मैं कुछ पी/आमंत्रण कोड कर रहा हूं जो IntPtrMarshal.AllocHGlobal के माध्यम से आवंटित करता है और स्वाभाविक रूप से, मैं अपने द्वारा बनाई गई अप्रबंधित स्मृति को साफ़ रूप से निपटाना चाहता हूं। तो मैं इस

using System.Runtime.InteropServices; 

[StructLayout(LayoutKind.Sequential)] 
public sealed class MemBlock : IDisposable 
{ 
    IntPtr ptr; 
    int length; 

    MemBlock(int size) 
    { 
      ptr = Marshal.AllocHGlobal(size); 
      length = size; 
    } 

    public void Dispose() 
    { 
      if (ptr != IntPtr.Zero) 
      { 
       Marshal.FreeHGlobal(ptr); 
       ptr = IntPtr.Zero; 
       GC.SuppressFinalize(this); 
      } 
    } 

    ~MemBlock() 
    { 
      Dispose(); 
    }  
} 

की तरह कुछ के बारे में सोच रहा हूँ मैं यह सोचते हैं कि क्योंकि MemBlock पूरी तरह से सील कर दिया है और कभी नहीं किया गया है अन्य वर्ग से निकला है कि एक virtual protected Dispose(bool disposing) को लागू करने की जरूरत नहीं है कर रहा हूँ।

इसके अलावा, finalizer अत्यंत आवश्यक होता है? सभी विचारों का स्वागत है।

उत्तर

13

finalizer आवश्यक है एक fallback तंत्र के रूप में अंत में मुक्त अप्रबंधित संसाधनों अगर आप Dispose कॉल करने के लिए भूल गया है।

नहीं, आपको sealed कक्षा में virtual विधि घोषित नहीं करना चाहिए। यह बिल्कुल संकलित नहीं होगा। साथ ही, sealed कक्षाओं में नए protected सदस्यों को घोषित करने की अनुशंसा नहीं की जाती है।

+0

लेकिन निश्चित रूप से इस मामले में कि एक बेस क्लास से प्राप्त एक मुहरबंद वर्ग तो एक आभासी निपटान आवश्यक होगा - सही? – zebrabox

+0

भी। फाइनलर का मतलब है फाइनेंजर कतार में जोड़ना और प्रभावी रूप से डबल कचरा इकट्ठा करने का ओवरहेड होना। अन-प्रबंधित संसाधनों का उपयोग करने के लिए भुगतान करने के लिए भारी जुर्माना लगता है। क्या प्रदर्शन हिट से बचने का कोई तरीका नहीं है? – zebrabox

+0

उस स्थिति में, आप विधि को ओवरराइड करेंगे। आप 'सीलबंद' वर्ग में 'वर्चुअल' के रूप में किसी भी तरीके की घोषणा नहीं कर सकते हैं। यह एक कंपाइलर ** त्रुटि ** है। –

7

एक मामूली जोड़; सामान्य मामले में, एक सामान्य पैटर्न Dispose(bool disposing) विधि है, ताकि आप जानते हैं कि आप Dispose (जहां अधिक चीजें उपलब्ध हैं) में अंतिम रूपक बनाम (जहां आपको वास्तव में किसी भी अन्य प्रबंधित प्रबंधित वस्तुओं को स्पर्श नहीं करना चाहिए) ।

उदाहरण के लिए:

public void Dispose() { Dispose(true); } 
~MemBlock() { Dispose(false); } 
void Dispose(bool disposing) { // would be protected virtual if not sealed 
    if(disposing) { // only run this logic when Dispose is called 
     GC.SuppressFinalize(this); 
     // and anything else that touches managed objects 
    } 
    if (ptr != IntPtr.Zero) { 
      Marshal.FreeHGlobal(ptr); 
      ptr = IntPtr.Zero; 
    } 
} 
+0

हाँ अच्छा बिंदु मार्क लेकिन अगर मुझे पता था कि मैं केवल अप्रबंधित संसाधनों का निपटान कर रहा था तो क्या यह कड़ाई से जरूरी है? – zebrabox

+0

इसके अलावा - बहुत बेवकूफ सवाल है, लेकिन अगर निपटान पैटर्न निश्चित रूप से अप्रबंधित संसाधनों को जारी करना है तो मैं जीसी द्वारा साफ किए जाने पर प्रबंधित संसाधनों के डिस्पोजेबल को क्यों संभालना चाहूंगा? – zebrabox

+0

यदि आप निर्धारक हैं, तो आप * जो भी आप * encapsulating * को साफ करना चाहते हैं; खासकर यदि वे स्वयं 'पहचानने योग्य' हैं। आप * इसे अंतिम रूप में नहीं करेंगे, क्योंकि वे पहले से ही एकत्र किए जा चुके हैं (और: यह अब आपका काम नहीं है)। और तुम सही हो; इस मामले में, 'SuppressFinalize' के अलावा (जो कि कोई फर्क नहीं पड़ता) हम कुछ भी प्रबंधित नहीं कर रहे हैं, इसलिए परेशान नहीं होना ठीक होगा; यही कारण है कि मैंने * सामान्य * मामले पर जोर दिया। –

7

से Joe Duffy's Weblog:

सील वर्गों के लिए, इस पद्धति का पालन नहीं होने की जरूरत है, यानी आप बस अपने finalizer को लागू करना चाहिए और सरल तरीकों के साथ निपटान (यानी ~ टी() (अंतिम रूप दें) और सी # में निपटान()। बाद वाला मार्ग चुनते समय, आपके कोड को अभी भी दिशानिर्देशों का पालन करना चाहिए अंतिमकरण के कार्यान्वयन और तर्क का निपटान करें।

तो हाँ, आप अच्छा होना चाहिए।

आप finalizer की जरूरत के रूप में Mehrdad उल्लेख करते हैं। यदि आप इससे बचना चाहते हैं, तो आप SafeHandle पर एक नज़र डालेंगे। मेरे पास सही उपयोग का सुझाव देने के लिए पी/Invoke के साथ पर्याप्त अनुभव नहीं है।

+0

धन्यवाद TrueWill! मैंने सेफहैंडल को देखा है और एरिक लिपर्ट के अनुसार इसे बीसीएल टीम द्वारा 'व्हिडबे' में पेश किए गए सबसे महत्वपूर्ण लाभों में से एक के रूप में देखा गया था (क्षमा करें अब के लिए लिंक नहीं मिल रहा है)। दुर्भाग्य से यह एक अमूर्त वर्ग है इसलिए आपको – zebrabox

+1

@zebrabox को हर तरह की स्थिति के लिए अपना खुद का रोल करना होगा: हालांकि आपको कुछ स्थितियों में अपना खुद का रोल करने की आवश्यकता हो सकती है, दस्तावेज़ीकरण कहता है: "सेफहैंडल से व्युत्पन्न प्री-लिखित कक्षाओं का एक सेट प्रदान किया गया है अमूर्त व्युत्पन्न, और यह सेट Microsoft.Win32.SafeHandles नामस्थान में स्थित है। " – TrueWill

+1

@TreueWill। हाँ बहुत सच है, लेकिन केवल फाइल हैंडल, प्रतीक्षा हैंडल, पाइप हैंडल और क्रिप्ट सामान की एक गुच्छा जैसी चीजों के लिए। कुछ भी नहीं से बेहतर! – zebrabox

1

आप एक सीलबंद कक्षा में आभासी तरीकों की घोषणा नहीं कर सकते हैं। एक सीलबंद कक्षा में संरक्षित सदस्यों को भी घोषित करना आपको एक कंपाइलर चेतावनी देता है। तो आपने इसे सही तरीके से कार्यान्वित किया है। कॉलिंग जीसी.SuppressFinalize (यह) अंतिम कारण के भीतर से स्पष्ट कारणों के लिए आवश्यक नहीं है लेकिन यह नुकसान नहीं पहुंचा सकता है।

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

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