【转】编写高质量代码改善C#程序的157个建议——建议49:在Dispose模式中应提取一个受保护的虚方法

 

建议49:在Dispose模式中应提取一个受保护的虚方法

在标准的Dispose模式中,真正的IDisposable接口的Dispose方法并没有做实际的清理工作,它其实是调用了下面的这个带bool参数且受保护的的虚方法:

        /// <summary>
        /// 非密封类修饰用protected virtual
        /// 密封类修饰用private
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
      //省略代码 }

之所以提供这样一个受保护的虚方法,是因为考虑了这个类型会被其他类型继承的情况。如果类型存在一个子类,子类也许会实现自己的Dispose模式。受保护的虚方法用来提醒子类:必须在自己的清理方法时注意到父类的清理工作,即子类需要在自己的释放方法中调用base.Dispose方法。

    public class DerivedSampleClass : SampleClass
    {
        //子类的非托管资源
        private IntPtr derivedNativeResource = Marshal.AllocHGlobal(100);
        //子类的托管资源
        private AnotherResource derivedManagedResource = new AnotherResource();
        //定义自己的是否释放的标识变量
        private bool derivedDisposed = false;

        /// <summary>
        ///重写父类Dispose方法
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            if (derivedDisposed)
            {
                return;
            }
            if (disposing)
            {
                // 清理托管资源
                if (derivedManagedResource != null)
                {
                    derivedManagedResource.Dispose();
                    derivedManagedResource = null;
                }
            }
            // 清理非托管资源
            if (derivedNativeResource != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(derivedNativeResource);
                derivedNativeResource = IntPtr.Zero;
            }
            //调用父类的清理代码
            base.Dispose(disposing);
            //让类型知道自己已经被释放
            derivedDisposed = true;
        }
    }

    public class SampleClass : IDisposable
    {
        //演示创建一个非托管资源
        private IntPtr nativeResource = Marshal.AllocHGlobal(100);
        //演示创建一个托管资源
        private AnotherResource managedResource = new AnotherResource();
        private bool disposed = false;

        /// <summary>
        /// 实现IDisposable中的Dispose方法
        /// </summary>
        public void Dispose()
        {
            //必须为true
            Dispose(true);
            //通知垃圾回收机制不再调用终结器(析构器)
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 不是必要的,提供一个Close方法仅仅是为了更符合其他语言(如
        /// C++)的规范
        /// </summary>
        public void Close()
        {
            Dispose();
        }

        /// <summary>
        /// 必须,防止程序员忘记了显式调用Dispose方法
        /// </summary>
        ~SampleClass()
        {
            //必须为false
            Dispose(false);
        }

        /// <summary>
        /// 非密封类修饰用protected virtual
        /// 密封类修饰用private
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposed)
            {
                return;
            }
            if (disposing)
            {
                // 清理托管资源
                if (managedResource != null)
                {
                    managedResource.Dispose();
                    managedResource = null;
                }
            }
            // 清理非托管资源
            if (nativeResource != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(nativeResource);
                nativeResource = IntPtr.Zero;
            }
            //让类型知道自己已经被释放
            disposed = true;
        }

        public void SamplePublicMethod()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("SampleClass", "SampleClass is disposed");
            }
            //省略
        }
    }

    class AnotherResource : IDisposable
    {
        public void Dispose()
        {
        }
    }


如果不为类提供这个受保护的虚方法,很有可能让开发者设计子类的时候忽略掉父类的清理工作。所以要在类型的Dispose模式中提供一个受保护的虚方法。

 

 

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

posted @ 2017-12-06 11:07  指间的徘徊  阅读(271)  评论(0编辑  收藏  举报