Tekkaman

导航

 

Implementing a Dispose method

0、Dispose() and Dispose(Boolean)

  The IDisposable interface requires the implementation of a single parameterless method, DisposeHowever, the dispose pattern requires two Dispose methods to be implemented:

  • A public non-virtual (NonInheritable in Visual Basic) IDisposable.Dispose implementation that has no parameters.

  • A protected virtual (Overridable in Visual Basic) Dispose method whose signature is:

    

1、Dispose() has a standard implementation, The Dispose method performs all object cleanup, so the garbage collector no longer needs to call the objects' Object.Finalizeoverride.

  实现System.IDsiposable.Dispose()方法。不能将此方法设置为virtual,子类不能override此方法。此方法的实现必须为如下代码。

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

2、实现析构函数(Finalize)。析构函数必须实现为以下代码。

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

3、实现virtual Dispose(bool disposing)方法,必须为protected。如果dispoing为true,说明从Dipose()方法调用而来;如果为false,说明从析构函数(Finalize)调用而来。在析构函数中,不能再使用引用类型(Ref)成员类型,所以只处理unmanaged resource的释放即可;而在Dipose()调用过程中,managed res & unmanaged res都要释放。

  最后,添加一个成员变量disposed来标记是否已经释放过。

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

            }
        }

3.1、Here's the general pattern for implementing the dispose pattern for a derived class that overrides Object.Finalize:

  A class derived from a class that implements the IDisposable interface shouldn't implement IDisposable, because the base class implementation of IDisposable.Dispose is inherited by its derived classes.

 1 using System;
 2 
 3 class DerivedClass : BaseClass
 4 {
 5    // Flag: Has Dispose already been called?
 6    bool disposed = false;
 7    
 8    // Protected implementation of Dispose pattern.
 9    protected override void Dispose(bool disposing)
10    {
11       if (disposed)
12          return; 
13       
14       if (disposing) {
15          // Free any other managed objects here.
16          //
17       }
18       
19       // Free any unmanaged objects here.
20       //
21       disposed = true;
22       
23       // Call the base class implementation.
24       base.Dispose(disposing);
25    }
26 
27    ~DerivedClass()
28    {
29       Dispose(false);
30    }
31 }

 

 4、An object must also call the Dispose method of its base class if the base class implements IDisposable

  如果基类有Dispose()方法,子类必须的Dispose()必须调用基类的Dispose()。

 5、什么时候需要Dispose()?

  1)包含Disposable对象的容器类需要实现Dipose,而不需要实现Finalize()。因为清空一个容器,并不表明需要释放unmanged resource。

  2)自身包含unmanged resource的类需实现Dispose、Finalize。

 6、DO throw an ObjectDisposedException from any member that cannot be used after the object has been disposed of.

  当调用一个已经Disposed对象时,抛出 ObjectDisposedException。

public class DisposableResourceHolder : IDisposable {  
    bool disposed = false;  
    SafeHandle resource; // handle to a resource  

    public void DoSomething(){  
           if(disposed) throw new ObjectDisposedException(...);  
        // now call some native methods using the resource   
            ...  
    }  
    protected virtual void Dispose(bool disposing){  
        if(disposed) return;  
        // cleanup  
        ...  
        disposed = true;  
    }  
}  

7、一些C#自带类库的Close()语言与Dispose()语义是一样的。

public class Stream : IDisposable {  
    IDisposable.Dispose(){  
        Close();  
    }  
    public void Close(){  
        Dispose(true);  
        GC.SuppressFinalize(this);  
    }  
}  

 

参考:

1、https://docs.microsoft.com/en-us/dotnet/api/system.idisposable.dispose?view=netframework-4.7.1

2、https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern

posted on 2017-11-22 14:35  Tekkaman  阅读(257)  评论(0编辑  收藏  举报