欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

探讨C#中Dispose方法与Close方法的区别详解

程序员文章站 2024-02-12 14:55:40
群里有人问,怎样直接清空堆里的string值。有人建议直接用dispose()方法;dispose()销毁了对象,是一种垃圾回收机制。(这里用using或许更好)当我们开发...

群里有人问,怎样直接清空堆里的string值。有人建议直接用dispose()方法;dispose()销毁了对象,是一种垃圾回收机制。(这里用using或许更好)
当我们开发c#代码的时候,经常碰到一个问题,有些class提供close(),有些class提供dispose(),那么dispose和close到底有什么区别?

在这里,要明确一下c#程序(或者说.net)中的资源。简单的说来,c#中的每一个类型都代表一种资源,而资源又分为两类:
托管资源:
由clr管理分配和释放的资源,即由clr里new出来的对象;
非托管资源:不受clr管理的对象,windows内核对象,如文件、数据库连接、套接字、com对象等;毫无例外地,如果我们的类型使用到了非托管资源,或者需要显式释放的托管资源,那么,就需要让类型继承接口idisposable。这相当于是告诉调用者,该类型是需要显式释放资源的,你需要调用我的dispose方法。

首先,dispose和close基本上应该是一样的。close是为了那些不熟悉dispose的开发者设计的。因为基本上所有的developer都知道close是干吗的(特别是对于那些有c++背景的developer)。
但是当我们写code时候,如果要实现close和dispose的时候,要注意close和dispose的设计模式。.net的一些class只提供close,而且派生自idisposable,并且隐藏了dispose方法。是不是觉得很不明白了?

对这些class来说,关键在于它们显式的(explicitly)实现了idisposable。对于隐式实现来说,你只需要调用"newa().dispose()",但是对于显式实现来说,dispose不会是这个class的成员函数。唯一的调用方式是你先要cast到idisposable才行。(“new a().dispose()”编译不过,但是“((idisposable)newa()).dispose()”可以编译过)。所以这样就符合了设计的要求:提供close(),隐藏dispose(),并且实现了idisposable接口。

在.net的framework里,close()被设计成public的,并且在close()里面call被隐藏的dispose();dispose()去call另一个virtual的dispose(bool)函数。所以如果你从这个class继承,你就必须实现dispose(bool)方法。

用者call close()的时候就会call到你重载的那个dispose(bool)方法去释放资源。
下面是一个标准的继承了idisposable接口类型的实现方式,这种实现我们称之为dispose模式:

复制代码 代码如下:

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