সঠিকভাবে আইডিস্পোজেবল কার্যকর করা হচ্ছে


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;
    }
}

ভিএস ২০১২-এ, আমার কোড বিশ্লেষণটি সঠিকভাবে আইডিস্পোজেবলকে কার্যকর করার জন্য বলেছে, তবে আমি এখানে ভুল কী করেছি তা নিশ্চিত নই।
সঠিক পাঠ্যটি নিম্নরূপ:

CA1063 কার্যকরভাবে আইডিস্পোজেবল কার্যকর করুন 'ব্যবহারকারী' এ ডিসপোজ (বুল) এর একটি ওভারডেবল বাস্তবায়ন সরবরাহ করুন বা সিল হিসাবে চিহ্নিত করুন। নিষ্পত্তি কল (মিথ্যা) একটি কল শুধুমাত্র দেশীয় সম্পদ পরিষ্কার করা উচিত। ডিসপোজ (সত্য) এর একটি কল পরিচালিত এবং স্থানীয় উভয় সংস্থান পরিষ্কার করতে হবে। stman User.cs 10

রেফারেন্সের জন্য: CA1063: আইডিস্পোজেবল সঠিকভাবে প্রয়োগ করুন

আমি এই পৃষ্ঠাটি পড়েছি তবে আমি ভয় করি যে এখানে কী করা দরকার তা আমি সত্যিই বুঝতে পারি না।

যদি কেউ আরও ল্যামেন্সের শর্তে সমস্যাটি কীভাবে এবং / অথবা কীভাবে আইডিস্পোজেবল কার্যকর করা উচিত তা ব্যাখ্যা করতে পারে, এটি সত্যই সহায়তা করবে!


1
এটি কি সমস্ত কোডের ভিতরে Dispose?
ক্লাদিও রেডি

42
আপনার ক্লাসের যে কোনও সদস্যকে ডিসপোজ () পদ্ধতিতে কল করতে আপনার ডিসপোজ () পদ্ধতিটি প্রয়োগ করা উচিত। এই সদস্যদের মধ্যে একটিও নেই। সুতরাং আপনার আইডিস্পোজেবল কার্যকর করা উচিত নয় । সম্পত্তি মান পুনরায় সেট করা অর্থহীন।
হান্স প্যাস্যান্ট

13
আপনি শুধুমাত্র বাস্তবায়ন প্রয়োজন IDispoableআপনি অপরিচালিত সম্পদের (এই অপরিচালিত সম্পদের আবৃত করা হয় (অন্তর্ভুক্ত মীমাংসা করা আছে যদি SqlConnection, FileStream, ইত্যাদি)। আপনি না করা উচিত নয় বাস্তবায়ন IDisposableযেমন এখানে আপনি শুধুমাত্র সম্পদ পরিচালিত হয়েছে। আইএমও'র হল, । কোড বিশ্লেষণের সঙ্গে একটি প্রধান সমস্যা এটা নিরীহ সামান্য নিয়ম চেক খুব ভাল, কিন্তু এর না ধারণাগত ত্রুটি পরীক্ষণ এ গুড।
জেসন

51
এটি আমার পক্ষে বেশ বিরক্তিকর যে কিছু লোক বরং এই ধারণাটিকে নীচে নামিয়ে দেখবে এবং এমন একটি ব্যক্তিকে সহায়তা করার প্রয়াসের চেয়ে বন্ধ হয়েছে যা স্পষ্টভাবে কোনও ধারণাকে ভুল বোঝে। কি লজ্জা.
অর্টান্ড

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(){ }যখনই সম্ভব সম্ভব ব্যবহার করা ভাল , তবে এটি করার জন্য আপনাকে আইডিস্পোজেবল কার্যকর করতে হবে, তাই সাধারণভাবে, আমি ইউএসিংয়ের মাধ্যমে ক্লাসে প্রবেশ করতে পছন্দ করি, esp। আমার যদি কেবলমাত্র এক বা দুটি ফাংশনে ক্লাসের প্রয়োজন হয়
অর্টান্ড

62
@ অর্টন্ড আপনি ভুল বুঝে গেছেন। শ্রেণি যখন আইডিজিপোজেবল প্রয়োগ করে তখন একটি usingব্লক ব্যবহার করা ভাল । ডিসপোজেবল হওয়ার জন্য যদি আপনার কোনও ক্লাসের প্রয়োজন না হয় তবে এটি প্রয়োগ করবেন না। এটি কোনও উদ্দেশ্য করে না।
ড্যানিয়েল মান

5
@ ড্যানিয়েলম্যান একটি usingব্লকের শব্দার্থবিজ্ঞানগুলি কেবল IDisposableইন্টারফেসের বাইরেও আবেদন করে । আমি কল্পনা করি যে IDisposableকেবলমাত্র স্কোপিংয়ের উদ্দেশ্যে কয়েকটি গালাগালি হয়েছে।
থমাস

1
পার্শ্ব-নোটের মতো যদি আপনার কোনও অব্যবহৃত সংস্থান মুক্ত করতে হয় তবে আপনি চূড়ান্ত কলিং ডিসপোজ (মিথ্যা) কলিংয়ের অন্তর্ভুক্ত করতে পারেন, যা জিসিকে ফ্যান্সালাইজারকে কল করতে হবে যখন আবর্জনা সংগ্রহের ক্ষেত্রে (যখন নিষ্পত্তি করা হয়নি এখনও ডাকা হয়েছে) এবং সঠিকভাবে বিনা ব্যবস্থাপনায় সম্পদ।
মারিওস্কি

4
আপনার বাস্তবায়নের কোনও চূড়ান্তকরণ ছাড়াই কলিং GC.SuppressFinalize(this);অর্থহীন। @ মারিওরোস্কি যেমন উল্লেখ করেছেন যে কোনও চূড়ান্তরক্ষক এটি নিশ্চিত করতে সহায়তা করবে যে Disposeক্লাসটি যদি কোনও usingব্লকের অভ্যন্তরে ব্যবহার না করা হয় তবে তা বলা হয়েছিল ।
হায়মো কটসবাচ

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করা উচিত নয় । আবর্জনা সংগ্রাহক fields ক্ষেত্রগুলির নিজস্ব যত্ন নেবেন।


1
এটির সাথে একমত হন - যখন এটির প্রয়োজন হয় না তখন সমস্ত কিছু নিষ্পত্তি করার ধারণা রয়েছে। নিষ্পত্তি কেবল তখনই ব্যবহার করা উচিত যখন আপনি পরিষ্কার করার জন্য নিয়ন্ত্রণহীন সংস্থান আছে !!
চন্দ্রমৌলেশ্বরন রবিচন্দ্র

4
কঠোরভাবে সত্য নয়, নিষ্পত্তি পদ্ধতি আপনাকে "পরিচালিত সংস্থানগুলি যা আইডিজিপোজেবল বাস্তবায়ন করে" নিষ্পত্তি করতে দেয়
ম্যাট উইলকো

@ ম্যাটওয়িলকো এটিকে অপরিকল্পিত সম্পদ নিষ্পত্তি করার একটি পরোক্ষ উপায় করে তোলে , কারণ এটি অপর একটি সংস্থানকে একটি নিয়ন্ত্রণহীন সম্পদ নিষ্পত্তি করার অনুমতি দেয়। এখানে অন্য পরিচালিত সংস্থার মাধ্যমে অপরিকল্পিত সংস্থান সম্পর্কে অপ্রত্যক্ষ রেফারেন্স নেই।
পরিবেশন করুন

@MattWilko নিষ্পত্তি স্বয়ংক্রিয়ভাবে কোনো পরিচালিত রিসোর্স যারা IDesposable বাস্তবায়িত ডেকে হবে
কলা কৌশল শর্মা

@ পঙ্কিশর্মা না, তা হবে না। এটি ম্যানুয়ালি কল করা প্রয়োজন । এটি এর পুরো বিষয়টি। আপনি ধরে নিতে পারবেন না যে এটি স্বয়ংক্রিয়ভাবে বলা হবে, আপনি কেবলমাত্র জানেন যে লোকেরা ম্যানুয়ালি এটি কল করার কথা , তবে লোকে ভুল করে ভুলে যায়।
পরিবেশিত

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
জিসি.সপ্রেসফাইনালাইজ (এটি) ডেস্ট্রাক্টরেও কল করা কি বুদ্ধিমানের কাজ হবে না? অন্যথায় বস্তুটি নিজেই পরবর্তী জিসিতে পুনরুদ্ধার করা হবে
সুধাংশু মিশ্র

2
@ ডটনেটগুই: জিসি চালানোর সময় অবজেক্টস ডেস্ট্রাক্টরকে ডাকা হয়। সুতরাং দু'বার কল করা সম্ভব নয়। এখানে দেখুন: msdn.microsoft.com/en-us/library/ms244737.aspx
schoetbi

1
সুতরাং এখন আমরা কি বয়লারপ্লেট কোডের কোনও অংশটিকে "প্যাটার্ন" বলছি?
চেল

4
@ আরডিএইচএস না আমরা নেই। দুটিই MSDN যুক্তরাষ্ট্রের এটা IS এখানে একটি প্যাটার্ন "নিষ্পত্তি প্যাটার্ন" - msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx তাই একটু আগে ডাউন ভোট হয়তো গুগল?
বেলোগিক্স

2
মাইক্রোসফ্ট বা আপনার পোস্ট উভয়ই প্যাটার্নটি দেখতে কেন এমন হওয়া উচিত তা পরিষ্কারভাবে জানায় না। সাধারণত, এটি এমনকি বয়লারপ্লেটও নয়, এটি কেবলমাত্র অতিমাত্রায় - SafeHandle(এবং উপ-প্রকারের) দ্বারা উত্পন্ন । পরিচালিত সংস্থাগুলির ক্ষেত্রে যথাযথ নিষ্পত্তি কার্যকর করার ক্ষেত্রে অনেক সহজ হয়ে যায়; আপনি void Dispose()পদ্ধতির একটি সাধারণ প্রয়োগের জন্য কোডটি নীচে ট্রিম করতে পারেন ।
ব্যাটারিব্যাকআপ ইউনিট

10

ক্লাসটি কোনও অ-পরিচালিত সংস্থান (ফাইল, ডাটাবেস সংযোগ ইত্যাদি) অর্জন না করায় আপনার Userক্লাস করার দরকার নেই । সাধারণত, আমরা ক্লাসগুলি চিহ্নিত করি যেন তাদের কমপক্ষে একটি ক্ষেত্র বা / এবং সম্পত্তি থাকে। বাস্তবায়ন করার সময় মাইক্রোসফ্ট টিপিক্যাল স্কিম অনুযায়ী আরও ভাল করে রাখুন:IDisposableIDisposableIDisposableIDisposable

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);
  } 
}

এটা সাধারণত কেস। তবে অন্যদিকে, ইউজিং কনস্ট্রাক্ট সি ++ স্মার্ট পয়েন্টারগুলির অনুরূপ কিছু লেখার সম্ভাবনা উন্মুক্ত করে, অর্থাত্ একটি অবজেক্ট যা কোনও ব্যবহারের ব্লক কীভাবে নির্গত হয় তা বিবেচনা না করে পূর্বের অবস্থাটিকে পুনরুদ্ধার করবে। আমি এটি করার একমাত্র উপায় হ'ল এইরকম একটি অবজেক্টকে আইডিজিপোজেবল বাস্তবায়ন করা। দেখে মনে হচ্ছে যে আমি এই জাতীয় প্রান্তিক ব্যবহারের ক্ষেত্রে সংকলকটির সতর্কতাটিকে এড়িয়ে যেতে পারি।
পাপা স্মুরফ

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

আমি মাইক্রোসফ্ট ডিসপোজ প্যাটার্নের প্রচুর উদাহরণ দেখতে পাচ্ছি যা সত্যই একটি অ্যান্টি-প্যাটার্ন। যেহেতু অনেকে প্রশ্নের কোডটি উল্লেখ করেছেন তাদের আইডিপোজেবলের মোটেই প্রয়োজন হয় না। তবে আপনি যদি এটি প্রয়োগ করতে যাচ্ছেন তবে দয়া করে মাইক্রোসফ্ট প্যাটার্নটি ব্যবহার করবেন না। আরও ভাল উত্তর এই নিবন্ধে পরামর্শ অনুসরণ করা হবে:

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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.