. Net IDisposable Interface

Source: Internet
Author: User
The garbage Collection in the. Net Framework helps programmers automatically reclaim managed resources, which is a comfortable experience for callers of class libraries: Any object can be created at any point, at any time, and the GC will always end up backstop. His shoes, what do you need to do to provide such a good experience when you are a library provider?

First, what are the managed resources within the. Net framework and which are unmanaged resources?

Basically, all classes within the. Net framework are managed resources, including a variety of streams (such as FileStream, MemoryStream), database connection, components, and so on.

Can write a simple small program verification: (Take FileStream as an example)

A method to monitor whether a file is being occupied in a background thread:

        private static void Monitorfilestatus (String fileName) {Console.WriteLine ("Start to monitor fil            E: {0} ", fileName); Task.Factory.StartNew (() = {while (true) {bool Isinuse =                    Isfileinuse (FileName); String Messageformat = Isinuse?                    ' File {0} is ' in use. ': ' file {0} is released. ';                    Console.WriteLine (Messageformat, FileName);                Thread.Sleep (Oneseconds);        }            });            } private static bool Isfileinuse (string fileName) {bool Isinuse = true;            FileStream stream = null;                try {stream = File.Open (FileName, Filemode.append, FileAccess.Write);            Isinuse = false;                } catch {} finally {if (stream! = null) {stream.  Dispose ();              }} return isinuse; }

To write a method that takes up a file, FileStream is just a local variable, and it should be recycled when the method returns:

        private static void OpenFile ()        {            FileStream stream  = File.Open (Testfilename, Filemode.append, FileAccess.Write);            Wait (fiveseconds);        }

The last is an essential waiting:

        private static void Wait (TimeSpan time)        {            Console.WriteLine ("Wait for {0} seconds ...", time. totalseconds);            Thread.Sleep (time);        }

Merging together is a test:
Start the file monitoring thread first, and then open the file without.
OpenFile method returns, predicting FileStream is recycled
Then call the GC to see if the file is released.

        private static void Filetest ()        {            monitorfilestatus (testfilename);            OpenFile ();            CALLGC ();            Wait (fiveseconds);        }

The result of the operation shows that the GC automatically recycles the FileStream automatically. There is no need to call the Dispose method or use the using

So, what are the unmanaged resources?

Typically, the PInvoke of Windows APIs, various IntPtr are unmanaged resources. For example, the same open file, if written as follows, includes an unmanaged resource

    [Flags] Internal enum Openfilestyle:uint {of_cancel = 0x00000800,//ignored.        For a dialog box with a Cancel button, use Of_prompt. Of_create = 0x00001000,//creates a new file.        If file exists, it is truncated to zero (0) length.        Of_delete = 0x00000200,//Deletes a file. Of_exist = 0x00004000,//Opens a file and then closes it. Used to test this a file exists Of_parse = 0x00000100,//Fills the OFSTRUCT structure, but does don't do anything E        Lse. Of_prompt = 0x00002000,//displays a dialog box if a requested file does not exist Of_read = 0x00000000,//Ope        NS a file for reading only.        Of_readwrite = 0x00000002,//Opens a file with Read/write permissions.        Of_reopen = 0x00008000,//Opens a file by using information in the REOPEN buffer. For ms-dos–based file systems, opens a file with compatibility mode, allows any process on a//specified Compu ter to open the file any number of TimEs. Other efforts to open a file with other sharing modes fail. This flag was mapped to the//file_share_read|        File_share_write Flags of the CreateFile function.        Of_share_compat = 0x00000000,//Opens a file without denying read or write access to other processes. On ms-dos-based file systems, if the file have been opened in compatibility mode/by any other process, the fun        Ction fails. This flag was mapped to the file_share_read|        File_share_write Flags of the CreateFile function.        Of_share_deny_none = 0x00000040,//Opens a file and denies read access to other processes. On ms-dos-based file systems, if the file have been opened in compatibility mode,//or for read access by any OT        Her process, the function fails.        This flag was mapped to the FILE_SHARE_WRITE flag of the CreateFile function. Of_share_deny_read = 0x00000030,//Opens a file and denies write access to other processEs. On ms-dos-based file systems, if a file have been opened in compatibility mode,//or for write access by any oth        Er process, the function fails.        This flag was mapped to the FILE_SHARE_READ flag of the CreateFile function. Of_share_deny_write = 0x00000020,//Opens a file with exclusive mode, and denies both Read/write access to other P        Rocesses. If a file has been opened in any other mode for read/write access, even by the current process,//the function        Fails. Of_share_exclusive = 0x00000010,//verifies that the date and time of a file is the same as when it is opened PR        eviously.        This is useful as a extra check for read-only files.        Of_verify = 0x00000400,//Opens a file for write access is only. Of_write = 0x00000001} [StructLayout (layoutkind.sequential)] internal struct ofstruct {public byte CB        Ytes;        public byte Ffixeddisc; Public UInt16 NerrcodE        Public UInt16 Reserved1;        Public UInt16 Reserved2;    [MarshalAs (UnmanagedType.ByValTStr, SizeConst = +)] public string szpathname;        } class WindowsAPI {[DllImport ("kernel32.dll", bestfitmapping = False, Throwonunmappablechar = True)] Internal static extern IntPtr OpenFile ([MarshalAs (UNMANAGEDTYPE.LPSTR)]string lpFileName, out Ofstruct Lpreopenbuff,        Openfilestyle Ustyle);        [DllImport ("kernel32.dll", SetLastError = True)]        [ReliabilityContract (Consistency.willnotcorruptstate, cer.success)]        [SuppressUnmanagedCodeSecurity]    [Return:marshalas (Unmanagedtype.bool)] internal static extern Bool CloseHandle (IntPtr hobject); }

To handle unmanaged resources, you need to implement IDisposable interface. There are two reasons:

Destructors cannot be relied upon because the invocation of a heterogeneous function is determined by the GC. Unable to release scarce resources in real time.

There is a general principle of processing: destructors handle managed resources, and IDisposable interface handle managed and unmanaged resources.

As the above example, the implementation code is completed as follows:

    public class Unmanagedfileholder:ifileholder, IDisposable {private IntPtr _handle;        private string _filename;        Public Unmanagedfileholder (String fileName) {_filename = FileName;            } public void OpenFile () {Console.WriteLine ("Open file with Windows API.");            Ofstruct info;        _handle = Windowsapi.openfile (_filename, out info, openfilestyle.of_readwrite);        } #region IDisposable Support private bool disposed = false; protected virtual void Dispose (bool disposing) {if (!disposed) {if (disposin g) {//No managed resource} windowsapi.closehandle (_hand                Le);                _handle = IntPtr.Zero;            disposed = true;        }} ~unmanagedfileholder () {Dispose (false);      } public void Dispose () {      Dispose (TRUE); Gc.        SuppressFinalize (this); } #endregion}

What if there are both managed resources and unmanaged resources in the same class?

You can follow the following pattern:

    Class Hybridpattern:idisposable    {        private bool _disposed = false;        ~hybridpattern ()        {            Dispose (false);        }        protected void Dispose (bool disposing)        {            if (_disposed)            {                return;            }            if (disposing)            {                //Code to dispose the managed resources of the class                //Internalcomponent1.dispose (); 
  }            //Code to dispose the un-managed resources of the class            //CloseHandle (handle);            handle = IntPtr.Zero;            _disposed = true;        }        public void Dispose ()        {            Dispose (true);            Gc. SuppressFinalize (this);        }    }

The following is a complete example of a managed FileStream, as well as an unmanaged Handler

    public class Hybridholder:ifileholder, IDisposable {private string _unmanagedfile;        private string _managedfile;        Private INTPTR _handle;        Private FileStream _stream;            Public Hybridholder (String unmanagedfile, String managedfile) {_unmanagedfile = Unmanagedfile;        _managedfile = Managedfile;            } public void OpenFile () {Console.WriteLine ("Open file with Windows API.");            Ofstruct info;            _handle = Windowsapi.openfile (_unmanagedfile, out info, openfilestyle.of_readwrite);            Console.WriteLine ("Open file with. Net libray.");        _stream = File.Open (_managedfile, Filemode.append, FileAccess.Write);        } #region IDisposable Support private bool disposed = false; protected virtual void Dispose (bool disposing) {if (!disposed) {//CONSOLE.WR Iteline ("string is null?")      {0} ", _stream = = null);          if (disposing && _stream! = null) {Console.WriteLine ("Clean up Manage                    D resource. "); _stream.                Dispose ();                } Console.WriteLine ("Clean Up Unmanaged resource.");                Windowsapi.closehandle (_handle);                _handle = IntPtr.Zero;            disposed = true;        }} ~hybridholder () {Dispose (false);            public void Dispose () {Dispose (true); Gc.        SuppressFinalize (this); } #endregion}

Finally, what if there is no class that implements IDisposable interface? For example byte[], StringBuilder

Do not interfere with their recycling at all, the GC is doing well.
Tried to set a large byte[] to null in a destructor, and the only result is that its collection is deferred to the next GC cycle.
The reason is also simple, each time a reference is brought to the count on its reference tree plus one.

Full code See Github:

Https://github.com/IGabriel/IDisposableSample

  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.