Finalize/Dispose pattern in C#

C# 2008

I have been working on this for a while now, and I am still confused about some issues. My questions are below

  • I know that you only need a finalizer if you are disposing of unmanaged resources. However, if you are using managed resources that make calls to unmanaged resources, would you still need to implement a finalizer?

  • However, if you develop a class that doesn't use any unmanaged resources, directly or indirectly, can you implement the IDisposable so that clients of your class can use the 'using statement'?

    Would it be acceptable to implement the IDisposable just so that clients of your class can use the using statement?

    using(myClass objClass = new myClass())
    {
        // Do stuff here
    }
    
  • I have developed this simple code below to demonstrate the Finalize/dispose pattern:

    public class NoGateway : IDisposable
    {
        private WebClient wc = null;
    
        public NoGateway()
        {
            wc = new WebClient();
            wc.DownloadStringCompleted += wc_DownloadStringCompleted;
        }
    
    
        // Start the Async call to find if NoGateway is true or false
        public void NoGatewayStatus()
        {
            // Start the Async's download
                // Do other work here
            wc.DownloadStringAsync(new Uri(www.xxxx.xxx));
        }
    
        private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            // Do work here
        }
    
        // Dispose of the NoGateway object
        public void Dispose()
        {
            wc.DownloadStringCompleted -= wc_DownloadStringCompleted;
            wc.Dispose();
            GC.SuppressFinalize(this);
        }
    }
    
  • Question about the source code:

  • Here I have not added the finalizer, and normally the finalizer will be called by the GC, and the finalizer will call the Dispose. As I don't have the finalizer, when do I call the Dispose method? Is it the client of the class that has to call it?

    So my class in the example is called NoGateway and the client could use and dispose of the class like this:

    using(NoGateway objNoGateway = new NoGateway())
    {
        // Do stuff here   
    }
    

    Would the Dispose method be automatically called when execution reaches the end of the using block, or does the client have to manually call the dispose method? ie

    NoGateway objNoGateway = new NoGateway();
    // Do stuff with object
    objNoGateway.Dispose(); // finished with it
    
  • I am using the webclient class in my NoGateway class. Because the webclient implements the IDisposable interface, does this mean that the webclient indirectly uses unmanaged resources? Is there a hard and fast rule to follow about this? How do I know that a class uses unmanaged resources?


  • The recommended IDisposable pattern is here. When programming a class that uses IDisposable, generally you should use two patterns:

    When implementing a sealed class that doesn't use unmanaged resources, you simply implement a Dispose method as with normal interface implementations:

    public sealed class A : IDisposable
    {
        public void Dispose()
        {
            // get rid of managed resources, call Dispose on member variables...
        }
    }
    

    When implementing an unsealed class, do it like this:

    public class B : IDisposable
    {    
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // get rid of managed resources
            }   
            // get rid of unmanaged resources
        }
    
        // only if you use unmanaged resources directly in B
        //~B()
        //{
        //    Dispose(false);
        //}
    }
    

    Notice that I haven't declared a finalizer in B ; you should only implement a finalizer if you have actual unmanaged resources to dispose. The CLR deals with finalizable objects differently to non-finalizable objects, even if SuppressFinalize is called.

    So, you shouldn't declare a finalizer unless you have to, but you give inheritors of your class a hook to call your Dispose and implement a finalizer themselves if they use unmanaged resources directly:

    public class C : B
    {
        private IntPtr m_Handle;
    
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                // get rid of managed resources
            }
            ReleaseHandle(m_Handle);
    
            base.Dispose(disposing);
        }
    
        ~C() {
            Dispose(false);
        }
    }
    

    If you're not using unmanaged resources directly ( SafeHandle and friends doesn't count, as they declare their own finalizers), then don't implement a finalizer, as the GC deals with finalizable classes differently, even if you later suppress the finalizer. Also note that, even though B doesn't have a finalizer, it still calls SuppressFinalize to correctly deal with any subclasses that do implement a finalizer.

    When a class implements the IDisposable interface, it means that somewhere there are some unmanaged resources that should be got rid of when you've finished using the class. The actual resources are encapsulated within the classes; you don't need to explicitly delete them. Simply calling Dispose() or wrapping the class in a using(...) {} will make sure any unmanaged resources are got rid of as necessary.


    The official pattern to implement IDisposable is hard to understand. I believe this one is better:

    public class BetterDisposableClass : IDisposable {
    
      public void Dispose() {
        CleanUpManagedResources();
        CleanUpNativeResources();
        GC.SuppressFinalize(this);
      }
    
      protected virtual void CleanUpManagedResources() { 
        // ...
      }
      protected virtual void CleanUpNativeResources() {
        // ...
      }
    
      ~BetterDisposableClass() {
        CleanUpNativeResources();
      }
    
    }
    

    An even better solution is to have a rule that you always have to create a wrapper class for any unmanaged resource that you need to handle:

    public class NativeDisposable : IDisposable {
    
      public void Dispose() {
        CleanUpNativeResource();
        GC.SuppressFinalize(this);
      }
    
      protected virtual void CleanUpNativeResource() {
        // ...
      }
    
      ~NativeDisposable() {
        CleanUpNativeResource();
      }
    
    }
    

    With SafeHandle and its derivatives, these classes should be very rare.

    The result for disposable classes that don't deal directly with unmanaged resources, even in the presence of inheritance, is powerful: they don't need to be concerned with unmanaged resources anymore . They'll be simple to implement and to understand:

    public class ManagedDisposable : IDisposable {
    
      public virtual void Dispose() {
        // dispose of managed resources
      }
    
    }
    

    Note that any IDisposable implementation should follow the below pattern (IMHO). I developed this pattern based on info from several excellent .NET "gods" the .NET Framework Design Guidelines (note that MSDN does not follow this for some reason!). The .NET Framework Design Guidelines were written by Krzysztof Cwalina (CLR Architect at the time) and Brad Abrams (I believe the CLR Program Manager at the time) and Bill Wagner ([Effective C#] and [More Effective C#] (just take a look for these on Amazon.com:

    Note that you should NEVER implement a Finalizer unless your class directly contains (not inherits) UNmanaged resources. Once you implement a Finalizer in a class, even if it is never called, it is guaranteed to live for an extra collection. It is automatically placed on the Finalization Queue (which runs on a single thread). Also, one very important note...all code executed within a Finalizer (should you need to implement one) MUST be thread-safe AND exception-safe! BAD things will happen otherwise...(ie undetermined behavior and in the case of an exception, a fatal unrecoverable application crash).

    The pattern I've put together (and written a code snippet for) follows:

    #region IDisposable implementation
    
    //TODO remember to make this class inherit from IDisposable -> $className$ : IDisposable
    
    // Default initialization for a bool is 'false'
    private bool IsDisposed { get; set; }
    
    /// <summary>
    /// Implementation of Dispose according to .NET Framework Design Guidelines.
    /// </summary>
    /// <remarks>Do not make this method virtual.
    /// A derived class should not be able to override this method.
    /// </remarks>
    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.
    
        // Always use SuppressFinalize() in case a subclass
        // of this type implements a finalizer.
        GC.SuppressFinalize( this );
    }
    
    /// <summary>
    /// Overloaded Implementation of Dispose.
    /// </summary>
    /// <param name="isDisposing"></param>
    /// <remarks>
    /// <para><list type="bulleted">Dispose(bool isDisposing) executes in two distinct scenarios.
    /// <item>If <paramref name="isDisposing"/> equals true, the method has been called directly
    /// or indirectly by a user's code. Managed and unmanaged resources
    /// can be disposed.</item>
    /// <item>If <paramref name="isDisposing"/> 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.</item></list></para>
    /// </remarks>
    protected virtual void Dispose( bool isDisposing )
    {
        // TODO If you need thread safety, use a lock around these 
        // operations, as well as in your methods that use the resource.
        try
        {
            if( !this.IsDisposed )
            {
                if( isDisposing )
                {
                    // TODO Release all managed resources here
    
                    $end$
                }
    
                // TODO Release all unmanaged resources here
    
    
    
                // TODO explicitly set root references to null to expressly tell the GarbageCollector
                // that the resources have been disposed of and its ok to release the memory allocated for them.
    
    
            }
        }
        finally
        {
            // explicitly call the base class Dispose implementation
            base.Dispose( isDisposing );
    
            this.IsDisposed = true;
        }
    }
    
    //TODO Uncomment this code if this class will contain members which are UNmanaged
    // 
    ///// <summary>Finalizer for $className$</summary>
    ///// <remarks>This finalizer will run only if the Dispose method does not get called.
    ///// It gives your base class the opportunity to finalize.
    ///// DO NOT provide finalizers in types derived from this class.
    ///// All code executed within a Finalizer MUST be thread-safe!</remarks>
    //  ~$className$()
    //  {
    //     Dispose( false );
    //  }
    #endregion IDisposable implementation
    

    Here is the code for implementing IDisposable in a derived class. Note that you do not need to explicitly list inheritance from IDisposable in the definition of the derived class.

    public DerivedClass : BaseClass, IDisposable (remove the IDisposable because it is inherited from BaseClass)
    
    
    protected override void Dispose( bool isDisposing )
    {
        try
        {
            if ( !this.IsDisposed )
            {
                if ( isDisposing )
                {
                    // Release all managed resources here
    
                }
            }
        }
        finally
        {
            // explicitly call the base class Dispose implementation
            base.Dispose( isDisposing );
        }
    }
    

    I've posted this implementation on my blog at: How to Properly Implement the Dispose Pattern

    链接地址: http://www.djcxy.com/p/9210.html

    上一篇: WCF vs ASP.NET Web API

    下一篇: 在C#中完成/处理模式