सही ढंग से आईडीसिसोपयोगी लागू करना


145

अपनी कक्षाओं में मैं इस प्रकार के रूप में आईडीसिसोप्लिक लागू करता हूं:

public class User : IDisposable
{
    public int id { get; protected set; }
    public string name { get; protected set; }
    public string pass { get; protected set; }

    public User(int UserID)
    {
        id = UserID;
    }
    public User(string Username, string Password)
    {
        name = Username;
        pass = Password;
    }

    // Other functions go here...

    public void Dispose()
    {
        // Clear all property values that maybe have been set
        // when the class was instantiated
        id = 0;
        name = String.Empty;
        pass = String.Empty;
    }
}

VS2012 में, मेरा कोड विश्लेषण आईडीसिसोपयोगी को सही तरीके से लागू करने के लिए कहता है, लेकिन मुझे यकीन नहीं है कि मैंने यहां क्या गलत किया है।
सटीक पाठ इस प्रकार है:

CA1063 'सही' पर डिस्पोजल (बूल) का एक अत्यधिक कार्यान्वयन प्रदान करें या सील किए गए प्रकार को चिह्नित करें। डिसपोज (झूठ) के लिए एक कॉल केवल देशी संसाधनों को साफ करना चाहिए। डिस्पोज (सच) के लिए एक कॉल प्रबंधित और देशी संसाधनों को साफ करना चाहिए। stman User.cs 10

संदर्भ के लिए: CA1063: सही ढंग से आईडीआईसप्लिमेंट को लागू करें

मैंने इस पृष्ठ के माध्यम से पढ़ा है, लेकिन मुझे डर है कि मैं वास्तव में यह नहीं समझता कि यहां क्या किया जाना चाहिए।

यदि कोई और अधिक लैंस शब्दों में समझा सकता है कि समस्या क्या है और / या आईडीआईसोपायरी को कैसे लागू किया जाना चाहिए, जो वास्तव में मदद करेगा!


1
क्या वह सब कोड अंदर है Dispose?
क्लाउडियो रेडी

42
आपको अपने वर्ग के किसी भी सदस्य पर डिस्पोज () पद्धति को कॉल करने के लिए अपनी डिस्पोज़ () पद्धति को लागू करना चाहिए। उन सदस्यों में से कोई भी एक नहीं है। इसलिए आपको आईडीसोपायरी को लागू नहीं करना चाहिए । संपत्ति मूल्यों को रीसेट करना व्यर्थ है।
हंस पैजेंट

13
आपको केवल लागू करने की आवश्यकता है IDispoableयदि आपके पास निपटान करने के लिए अप्रबंधित संसाधन हैं (इसमें अप्रबंधित संसाधन शामिल हैं जो लिपटे हुए हैं ( SqlConnectionऔर FileStream, आदि)। आपको लागू नहीं करना चाहिए और IDisposableयदि आपके पास केवल यहां जैसे संसाधन प्रबंधित नहीं हैं, तो यह है, IMO। कोड विश्लेषण के साथ एक बड़ी समस्या। यह मूर्खतापूर्ण छोटे नियमों की जांच करने में बहुत अच्छा है, लेकिन वैचारिक त्रुटियों की जांच करने में अच्छा नहीं है
जेसन

51
यह मेरे लिए काफी परेशान करने वाला है कि कुछ लोग बल्कि इस सवाल को बंद कर देंगे और इस सवाल को एक ऐसे व्यक्ति की मदद करने की कोशिश से बंद कर देंगे जिसने स्पष्ट रूप से एक अवधारणा को गलत समझा है। कितनी शर्म की बात है।
Ortund

2
तो निराश न करें, अपवोट न करें, पोस्ट को शून्य पर छोड़ दें और सहायक पॉइंटर के साथ प्रश्न को बंद करें।
tjmoore

जवाबों:


113

यह सही कार्यान्वयन होगा, हालांकि मुझे आपके द्वारा पोस्ट किए गए कोड में कुछ भी नहीं देखना है। आपको केवल तभी लागू करना होगा IDisposableजब:

  1. आपके पास अप्रबंधित संसाधन हैं
  2. आप उन चीजों के संदर्भों को पकड़ रहे हैं जो स्वयं प्रयोज्य हैं।

आपके द्वारा पोस्ट किए गए कोड में कुछ भी निस्तारण की आवश्यकता नहीं है।

public class User : IDisposable
{
    public int id { get; protected set; }
    public string name { get; protected set; }
    public string pass { get; protected set; }

    public User(int userID)
    {
        id = userID;
    }
    public User(string Username, string Password)
    {
        name = Username;
        pass = Password;
    }

    // Other functions go here...

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

    protected virtual void Dispose(bool disposing)
    {
        if (disposing) 
        {
            // free managed resources
        }
        // free native resources if there are any.
    }
}

2
मुझे बताया गया था जब मैंने सी # में लिखना शुरू किया था कि जब using(){ }भी संभव हो, इसका उपयोग करना सबसे अच्छा है, लेकिन ऐसा करने के लिए, आपको आईडीसिसोप्लग लागू करने की आवश्यकता है, इसलिए सामान्य तौर पर, मैं usings, esp के माध्यम से एक वर्ग का उपयोग करना पसंद करता हूं। अगर मुझे केवल एक या दो कार्यों में कक्षा की आवश्यकता है
Ortund

62
@ ओरतुंड आपने गलत समझा। जब क्लास IDisposable को लागू करता है तोusing ब्लॉक का उपयोग करना सबसे अच्छा है । यदि आपको डिस्पोजेबल होने के लिए किसी वर्ग की आवश्यकता नहीं है, तो इसे लागू न करें। यह बिना किसी उद्देश्य के कार्य करता है।
डैनियल मैन

5
@DanielMann usingब्लॉक के शब्दार्थ IDisposableअकेले इंटरफ़ेस से परे अपील करते हैं, हालांकि। मैं कल्पना करता हूं कि IDisposableसिर्फ डांटने के मकसद से कुछ गालियां दी गई हैं।
थॉमस

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

4
आपके कार्यान्वयन में अंतिम रूप दिए बिना कॉल GC.SuppressFinalize(this);करना व्यर्थ है। जैसा कि @mariozski ने बताया कि यह सुनिश्चित करने में मदद करेगा कि Disposeक्लास को किसी usingब्लॉक के अंदर इस्तेमाल नहीं किया जाता है ।
14:24 बजे हायमो कुत्स्चबैक

57

सबसे पहले, आप "स्वच्छ अप" की जरूरत नहीं है stringऔर intरों - वे कचरा कलेक्टर द्वारा स्वचालित रूप से का ध्यान रखा जाना होगा। केवल एक चीज जिसे साफ करने की आवश्यकता है वह है Disposeअप्रबंधित संसाधन या कार्यान्वित किए गए पुनरावर्ती प्रबंधन IDisposable

हालांकि, यह मानते हुए कि यह केवल एक सीखने की कवायद है, इसे लागू करने का अनुशंसित तरीका IDisposable"सुरक्षा पकड़" जोड़ना है ताकि यह सुनिश्चित हो सके कि किसी भी संसाधन को दो बार निपटाया नहीं गया है:

public void Dispose()
{
    Dispose(true);

    // Use SupressFinalize in case a subclass 
    // of this type implements a finalizer.
    GC.SuppressFinalize(this);   
}
protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing) 
        {
            // Clear all property values that maybe have been set
            // when the class was instantiated
            id = 0;
            name = String.Empty;
            pass = String.Empty;
        }

        // Indicate that the instance has been disposed.
        _disposed = true;   
    }
}

3
+1, यह सुनिश्चित करने के लिए कि कोड को केवल एक बार साफ करने के लिए एक झंडा लगा है, जिस तरह से, गुणों को शून्य या जो कुछ भी करने की तुलना में बेहतर है (विशेषकर चूंकि readonlyशब्दार्थ के साथ हस्तक्षेप होता है)
थॉमस

उपयोगकर्ता कोड का उपयोग करने के लिए +1 (भले ही यह स्वचालित रूप से साफ हो जाएगा) यह स्पष्ट करने के लिए कि वहां क्या जाता है। इसके अलावा, एक नमकीन नाविक नहीं होने के लिए और यहां पर कई अन्य लोगों की तरह सीखने के दौरान एक छोटी सी गलती करने के लिए उसे हथौड़ा दिया।
मर्फीब्रॉ 2

42

निम्नलिखित उदाहरण IDisposableइंटरफ़ेस को लागू करने के लिए सामान्य सर्वोत्तम अभ्यास को दर्शाता है। संदर्भ

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

public class DisposeExample
{
    // A base class that implements IDisposable. 
    // By implementing IDisposable, you are announcing that 
    // instances of this type allocate scarce resources. 
    public class MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource. 
        private IntPtr handle;
        // Other managed resource this class uses. 
        private Component component = new Component();
        // Track whether Dispose has been called. 
        private bool disposed = false;

        // The class constructor. 
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }

        // Implement IDisposable. 
        // Do not make this method virtual. 
        // A derived class should not be able to override this method. 
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method. 
            // Therefore, you should call GC.SupressFinalize to 
            // take this object off the finalization queue 
            // and prevent finalization code for this object 
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios. 
        // If disposing equals true, the method has been called directly 
        // or indirectly by a user's code. Managed and unmanaged resources 
        // can be disposed. 
        // If disposing equals false, the method has been called by the 
        // runtime from inside the finalizer and you should not reference 
        // other objects. Only unmanaged resources can be disposed. 
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called. 
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources. 
                if(disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }

                // Call the appropriate methods to clean up 
                // unmanaged resources here. 
                // If disposing is false, 
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;

            }
        }

        // Use interop to call the method necessary 
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        // Use C# destructor syntax for finalization code. 
        // This destructor will run only if the Dispose method 
        // does not get called. 
        // It gives your base class the opportunity to finalize. 
        // Do not provide destructors in types derived from this class.
        ~MyResource()
        {
            // Do not re-create Dispose clean-up code here. 
            // Calling Dispose(false) is optimal in terms of 
            // readability and maintainability.
            Dispose(false);
        }
    }
    public static void Main()
    {
        // Insert code here to create 
        // and use the MyResource object.
    }
}

14

IDisposableआपके लिए बिना साधन वाले संसाधनों को साफ करने के लिए एक साधन प्रदान करने के लिए मौजूद है जो कचरा कलेक्टर द्वारा स्वचालित रूप से साफ नहीं किया जाएगा।

आपके द्वारा "सफाई" किए जा रहे सभी संसाधन प्रबंधित संसाधन हैं, और जैसे कि आपका Disposeतरीका कुछ भी पूरा नहीं कर रहा है। आपकी कक्षा को बिल्कुल भी लागू नहीं करना चाहिए IDisposable। कचरा संग्रहकर्ता उन सभी क्षेत्रों की देखभाल करेगा जो अपने आप ही ठीक होंगे।


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

4
कड़ाई से सच नहीं है, डिस्पोज़ विधि आपको "प्रबंधित संसाधनों को लागू करने की अनुमति देता है जो आईडीसिसोप्लीक को लागू करता है"
मैट विल्को

@MattWilko जो इसे अप्रबंधित संसाधनों के निपटान का एक अप्रत्यक्ष तरीका बनाता है , क्योंकि यह एक अन्य संसाधन को एक अप्रबंधित संसाधन के निपटान की अनुमति देता है। यहाँ एक अप्रबंधित संसाधन का अप्रत्यक्ष संदर्भ अन्य प्रबंधित संसाधन के माध्यम से भी नहीं है ।
सर्विस

@ मट्टविल्को डिस्पोजल स्वचालित रूप से किसी भी प्रबंधित संसाधन में बुलाया जाएगा, जो लागू किया गया है
panky sharma

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

14

आपको इस तरह से डिस्पोजेबल पैटर्न का उपयोग करने की आवश्यकता है :

private bool _disposed = false;

protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing)
        {
            // Dispose any managed objects
            // ...
        }

        // Now disposed of any unmanaged objects
        // ...

        _disposed = true;
    }
}

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

// Destructor
~YourClassName()
{
    Dispose(false);
}

1
यह विध्वंसक के रूप में अच्छी तरह से GC.SuppressFinalize (यह) के लिए एक कॉल करने के लिए समझदार नहीं होगा? अन्यथा वस्तु को अगले GC
सुधांशु मिश्रा

2
@dotnetguy: gc के चलने पर ऑब्जेक्ट्स डिस्ट्रक्टर को कहा जाता है। इसलिए दो बार कॉल करना संभव नहीं है। यहां देखें: msdn.microsoft.com/en-us/library/ms244737.aspx
schoetbi

1
तो अब हम बॉयलरप्लेट कोड के किसी भी टुकड़े को "पैटर्न" कह रहे हैं?
चेल

4
@ हम नहीं हैं। MSDN ने कहा है कि एक पैटर्न " डिस्पोज़ पैटर्न" यहाँ है - msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx तो नीचे वोटिंग से पहले शायद Google थोड़ा हो?
बेलगॉइस

2
न तो Microsoft और न ही आपकी पोस्ट स्पष्ट रूप से बताती है कि पैटर्न इस तरह क्यों दिखना चाहिए। आम तौर पर, यह बॉयलरप्लेट भी नहीं है, यह सिर्फ सतही है - SafeHandleऔर (और उप प्रकार) से घिरा हुआ है । प्रबंधित संसाधनों के मामले में उचित निपटान लागू करना अधिक सरल हो जाता है; आप void Dispose()विधि को सरल कार्यान्वयन के लिए नीचे कोड ट्रिम कर सकते हैं ।
बैटरीबाकअपयूनीट सेप

10

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

public class User: IDisposable {
  ...
  protected virtual void Dispose(Boolean disposing) {
    if (disposing) {
      // There's no need to set zero empty values to fields 
      // id = 0;
      // name = String.Empty;
      // pass = String.Empty;

      //TODO: free your true resources here (usually IDisposable fields)
    }
  }

  public void Dispose() {
    Dispose(true);

    GC.SuppressFinalize(this);
  } 
}

ऐसा इसलिए है आमतौर पर मामला। लेकिन दूसरी ओर, उपयोग करने वाला निर्माण C ++ स्मार्ट पॉइंटर्स के समान कुछ लिखने की संभावना को खोलता है, अर्थात् एक ऑब्जेक्ट जो पिछली स्थिति को पुनर्स्थापित करेगा चाहे कोई ब्लॉक का उपयोग कैसे किया जाए। मुझे ऐसा करने का एकमात्र तरीका इस तरह की वस्तु को लागू करना है। ऐसा लगता है कि मैं इस तरह के सीमांत उपयोग के मामले में संकलक की चेतावनी को अनदेखा कर सकता हूं।
पापा स्मर्फ

3

जब भी आप एक नियतात्मक (पुष्टि) कचरा संग्रह चाहते हैं, तो इडीसोपायरी लागू होती है।

class Users : IDisposable
    {
        ~Users()
        {
            Dispose(false);
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
            // This method will remove current object from garbage collector's queue 
            // and stop calling finilize method twice 
        }    

        public void Dispose(bool disposer)
        {
            if (disposer)
            {
                // dispose the managed objects
            }
            // dispose the unmanaged objects
        }
    }

स्पष्ट रूप से कॉलिंग डिस्पोज़ विधि से बचने के लिए उपयोगकर्ता वर्ग का उपयोग "ब्लॉक" का उपयोग करके बनाते और करते हुए:

using (Users _user = new Users())
            {
                // do user related work
            }

उपयोग किए गए ब्लॉक के अंत में बनाया गया उपयोगकर्ता ऑब्जेक्ट डिस्पोज़ विधि के अंतर्निहित आह्वान द्वारा निपटाया जाएगा।


2

मैं माइक्रोसॉफ्ट डिस्पोज़ पैटर्न के बहुत सारे उदाहरण देखता हूं जो वास्तव में एक विरोधी पैटर्न है। जैसा कि कई लोगों ने बताया है कि प्रश्न में कोड के लिए आईडीसिसोपोल की आवश्यकता नहीं है। लेकिन अगर आप इसे लागू करने जा रहे हैं, तो कृपया Microsoft पैटर्न का उपयोग न करें। इस लेख में सुझावों का बेहतर उत्तर दिया जाएगा:

https://www.codeproject.com/Articles/29534/IDisposable-What-Your-Mother-Never-Told-You-About

केवल दूसरी चीज़ जो मददगार होगी वह उस कोड विश्लेषण चेतावनी को दबा रही है ... https://docs.microsoft.com/en-us/visualstudio/code-quality/in-source-suppression-overview?view=vs- 2017

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