C#中的IDisposable模式

当谈到垃圾回收,在C#中,托管资源的垃圾回收是通过CLR的Garbage Collection来实现的,Garbage Collection会调用堆栈上对象的析构函数完成对象的释放工作;而对于一些非托管资源,比如数据库链接对象等,需要实现IDisposable接口进行手动的垃圾回收。那么什么时候使用Idisposable接口,以及如何使用呢?

public interface IDisposable
{
    void Dispose();
}

public class DisposablClass : IDisposable
{
    //是否回收完毕
    bool _disposed;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~DisposableClass()
    {
        Dispose(false);
    }

    //这里的参数表示示是否需要释放那些实现IDisposable接口的托管对象
    protected virtual void Dispose(bool disposing)
    {
        if(_disposed) return; //如果已经被回收,就中断执行
        if(disposing)
        {
            //TODO:释放那些实现IDisposable接口的托管对象
        }

        //TODO:释放非托管资源,设置对象为null

        _disposed = true;
    }
}

Dispose()方法

当需要回收非托管资源的DisposableClass类,就调用Dispoase()方法。而这个方法不会被CLR自动调用,需要手动调用。

~DisposableClass(),析构函数

当托管堆上的对象没有被其它对象引用,GC会在回收对象之前,调用对象的析构函数。这里的~DisposableClass()析构函数的意义在于告诉GC你可以回收我,Dispose(false)表示在GC回收的时候,就不需要手动回收了。

虚方法Dispose(bool disposing)

通过此方法,所有的托管和非托管资源都能被回收。参数disposing表示是否需要释放那些实现IDisposable接口的托管对象。

如果disposings设置为true,就表示DisposablClass类依赖某些实现了IDisposable接口的托管对象,可以通过这里的Dispose(bool disposing)方法调用这些托管对象的Dispose()方法进行回收。

如果disposings设置为false,就表示DisposableClass类依赖某些没有实现IDisposable的非托管资源,那就把这些非托管资源对象设置为null,等待GC调用DisposableClass类的析构函数,把这些非托管资源进行回收。

另外,以上把Dispose(bool disposing)方法设置为protected virtual的原因是希望有子类可以一起参与到垃圾回收逻辑的设计,而且还不会影响到基类。比如有这样的一个子类:

public class SubDisposableClass : DiposableClass
{
    private bool _disposed; //表示是否已经被回收

    protected override void Dispose(bool disposing)
    {
        if(!_disposed) //如果还没有被回收
        {
            if(disposiing) //如果需要回收一些托管资源
            {
                //TODO:回收托管资源,调用IDisposable的Dispose()方法就可以
            }

            //TODO:回收非托管资源,把之设置为null,等待CLR调用析构函数的时候回收

            _disposed = true;
        }

        base.Dispose(disposing);//再调用父类的垃圾回收逻辑
    }
}


在.NET 2.0之前,如果一个对象的析构函数抛出异常,这个异常会被CLR忽略。但.NET 2.0以后,如果析构函数抛出异常就会导致应用程序的崩溃。所以,保证析构函数不抛异常变得非常重要。

还有,Dispose()方法允许抛出异常吗?答案是否定的。如果Dispose()方法有抛出异常的可能,那就需要使用try/catch来手动捕获。以下是考虑Dispose()方法有异常可能的写法:

public class DisposableClass : IDisposable
{
    bool _disposed;

    ......

    protected virtual void Dispose(bool disposing)
    {
        if(_disposed) return;

        if(disposing)
        {
            //TODO:调用托管资源的Dispose()方法进行垃圾回收
        }

        try
        {
            _channelFactory.Close(); //关闭的时候可能会有异常
        }
        catch(Exception ex)
        {
            _log.Warn(ex);//记录日志

            try
            {
                _channelFactory.Abort();//丢弃的时候可能会有异常
            }
            catch(Exception cex)
            {
                _log.Warn(cex);//记录日志
            }
        }

        _channelFactory = null;
        _disposed = true;
    }
}


总结:当我们自定义的类及其业务逻辑中引用某些托管和非托管资源,就需要实现IDisposable接口,实现对这些资源对象的垃圾回收。

参考资料:

http://www.cnblogs.com/lori/p/3535470.html
http://lostechies.com/chrispatterson/2012/11/29/idisposable-done-right/

时间: 2024-12-06 15:26:00

C#中的IDisposable模式的相关文章

C#中的IDisposable模式用法详解

本文实例讲述了C#中IDisposable模式的用法,针对垃圾资源的回收进行了较为详细的讲解.分享给大家供大家参考之用.具体方法如下: 首先,对于垃圾回收而言,在C#中,托管资源的垃圾回收是通过CLR的Garbage Collection来实现的,Garbage Collection会调用堆栈上对象的析构函数完成对象的释放工作:而对于一些非托管资源,比如数据库链接对象等,需要实现IDisposable接口进行手动的垃圾回收.那么什么时候使用Idisposable接口,以及如何使用呢? 先来参考一

[转]改善C#程序的建议4:C#中标准Dispose模式的实现

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

【转】C#中对IDisposable接口的理解

IDisposable接口定义:定义一种释放分配的资源的方法. .NET 平台在内存管理方面提供了GC(Garbage Collection),负责自动释放托管资源和内存回收的工作,但它无法对非托管资源进行释放,这时我们必须自己提供方法来释放对象内分配的非托管资源,比如你在对象的实现代码中使用了一个COM对象 最简单的办法可以通过实现Finalize()来释放非托管资源,因为GC在释放对象时会检查该对象是否实现了 Finalize() 方法. 有一种更好的,那就是通过实现一个接口显式的提供给客户

C#中对IDisposable接口的理解

http://blog.sina.com.cn/s/blog_8abeac5b01019u19.html 本人最近接触一个项目,在这个项目里面看到很多类实现了IDisposable接口.在我以前的项目中都很少用过这个接口,只知道它是用来手动释放资源的.这么多地方用应该有它的好处,为此自己想对它有进一步的了解,但这个过程远没有我想象中的简单. IDisposable接口定义:定义一种释放分配的资源的方法. .NET 平台在内存管理方面提供了GC(Garbage Collection),负责自动释放

改善C#程序的建议4:C#中标准Dispose模式的实现

原文:改善C#程序的建议4:C#中标准Dispose模式的实现 需要明确一下C#程序(或者说.NET)中的资源.简单的说来,C#中的每一个类型都代表一种资源,而资源又分为两类: 托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象: 非托管资源:不受CLR管理的对象,windows内核对象,如文件.数据库连接.套接字.COM对象等: 毫无例外地,如果我们的类型使用到了非托管资源,或者需要显式释放的托管资源,那么,就需要让类型继承接口IDisposable.这相当于是告诉调用者,该

MVC中的Repository模式

1.首先创建一个空的MVC3应用程序,命名为MyRepository.Web,解决方案命名为MyRepository. 2.添加一个类库项目,命名为MyRepository.DAL,添加一个文件夹命名为Repository来存放业务逻辑. 3.继续添加一个类库项目,命名为MyRepository.Domain,添加两个文件夹Models和Infrastructure. Models来存放实体,Infrastructure来存放几个基本的类.现在目录结构已经搭建好了. 4.用NuGet确保三个项目

PHP中的抽象类与抽象方法/静态属性和静态方法/PHP中的单利模式(单态模式)/串行化与反串行化(序列化与反序列化)/约束类型/魔术方法小结

  前  言  OOP  学习了好久的PHP,今天来总结一下PHP中的抽象类与抽象方法/静态属性和静态方法/PHP中的单利模式(单态模式)/串行化与反串行化(序列化与反序列化). 1  PHP中的抽象类与抽象方法 1.什么是抽象方法?              没有方法体 {} 的方法,必须使用abstract 关键字修饰.这样的方,我们叫做抽象方法.                    abstract function say(); //    抽象方法 2.什么是抽象类?        

在 shell 中使用 vi 模式

作为一名大型开源社区的参与者,更确切地说,作为 Fedora 项目的成员,我有机会与许多人会面并讨论各种有趣的技术主题. 我最喜欢的主题是"命令行"或者说 shell,因为了解人们如何熟练使用 shell 可以让你深入地了解他们的想法,他们喜欢什么样的工作流程,以及某种程度上是什么激发了他们的灵感. 许多开发和运维人员在互联网上公开分享他们的" dot 文件"(他们的 shell 配置文件的常见俚语),这将是一个有趣的协作机会,让每个人都能从对命令行有丰富经验的人中

php中的组合模式

刚看完了<深入php面向对象.模式与实践>一书中组合模式这块内容,为了加深理解和记忆,所以着手写了这篇博客. 为方便后续理解,此处先引入两个概念,局部对象和组合对象. 局部对象:无法将其他对象组合到自身内部属性上的对象.即不能组合其他对象的对象. 组合对象:可以将其他对象组合到自身内部属性上的对象.即可以组合其他对象的对象. 注:将对象A的某个属性中存储着对象B对象的引用,则表示A与B有组合关系,其中A将B组合到了自身内部. 首先我们通过给出下面的业务需求,来引入组合模式: 业务部门想要开发一