zoukankan      html  css  js  c++  java
  • 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/

  • 相关阅读:
    C# 设计模式-抽象工厂模式
    C# 设计模式-工厂方法模式
    C# 设计模式-简单工厂模式
    C# 设计原则-迪米特法则(最少知识原则)
    C# 设计原则-接口隔离原则
    阻止右击事件并更改为自定义导航栏;
    今日头条滚动新闻版块特效
    抓包工具
    查看页面加载速度
    插件那点事
  • 原文地址:https://www.cnblogs.com/darrenji/p/3959119.html
Copyright © 2011-2022 走看看