登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

秒大刀 博客

好好学习 天天向上

 
 
 

日志

 
 
 
 

C# IDisposable  

2009-11-27 16:53:58|  分类: C# |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

    C#中昂贵资源的释放是通过手工调用IDisposable.Dispose方法来进行的,更有using语句可以帮助用户及时调用Dispose方法,这在存在异常抛出的情况下非常有用。

    MSDN对IDisposable接口的解释为:定义一种释放分配的资源的方法。此接口的主要用途是释放非托管资源。当不再使用托管对象时,垃圾回收器会自动释放分配给该对象的内存。但无法预测进行垃圾回收的时间。另外,垃圾回收器对窗口句柄或打开的文件和流等非托管资源一无所知。将此接口的 Dispose 方法与垃圾回收器一起使用来显式释放非托管资源。当不再需要对象时,对象的使用者可以调用此方法。

    通常要实现自己的IDisposable子类时,写法如下(其中的Dispose方法可以Alt+Shift+F10自动生成的):

class Demo : System.IDisposable

{

     #region IDisposable 成员

 

     public void Dispose()

     {

         throw new System.NotImplementedException();

     }

 

     #endregion

}

    对Demo的使用方法如下:

Demo demo = new Demo();

// do something, but throw exceptions.

demo.Dispose();

    当然为了防止Dispose方法忘记调用,也可以不厌其烦的写上:

Demo demo = new Demo();

try

{

     //

}

finally

{

     demo.Dispose();

}

   也可以用nxusing语句

using (Demo demo = new Demo())

{

     // do anything, even throw an exception.

}

    这样既省了手工调用Dispose方法的麻烦,也能在using语句块中异常抛出时保证Dispose方法正常被调用(这有点让人想起lock语句)。忘记Dispose方法的调用会造成内存泄露(别以为C#就不漏了C IDisposable - 秒大刀 - 秒大刀的城堡

    更高级的IDisposable实现参考以下代码,可以精确控制资源回收:

class Demo : System.IDisposable

{

     private bool disposed = false  // 保证多次调用Dispose方式不会抛出异常

 

     #region IDisposable 成员

 

     //可以被客户直接调用

     public void Dispose()

     {

         //必须以Dispose(true)方式调用,以true告诉Dispose(bool disposing)函数是被客户直接调用的

         Dispose(true);     // MUST be 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); // 告诉垃圾回收器从Finalization队列中清除自己,从而阻止垃圾回收器调用Finalize方法.        

     }

 

     #endregion

     // 无法被客户直接调用
     // 如果 disposing 是 true, 那么这个方法是被客户直接调用的,那么托管的,和非托管的资源都可以释放
     // 如果 disposing 是 false, 那么函数是从垃圾回收器在调用Finalize时调用的,此时不应当引用其他托管对象所以,只能释放非托管资源

     protected virtual void Dispose(bool disposing)

     {

         // If you need thread safety, use a lock around these operations, as well as in your methods that use the resource.

         // Check to see if Dispose has already been called

         if (disposed)

              return;

         if (disposing) // 这个方法是被客户直接调用的,那么托管的,和非托管的资源都可以释放

         {

              // 在这里释放托管资源

         }

         // 在这里释放非托管资源

         disposed = true; // Indicate that the instance has been disposed

     }

     // 析构函数自动生成 Finalize 方法和对基类的 Finalize 方法的调用.默认情况下,一个类是没有析构函数的,也就是说,对象被垃圾回收时不会被调用Finalize方法

     ~Demo()

     {

          // 为了保持代码的可读性性和可维护性,千万不要在这里写释放非托管资源的代码
          // 必须以Dispose(false)方式调用,以false告诉Dispose(bool disposing)函数是从垃圾回收器在调用Finalize时调用的

         Dispose(false);    // MUST be false

     }

}

    以上代码中带参数的Dispose方法可以写成private,但如果要写成protected 最好也加上virtual,以便子类定制。但绝对不能写成public的,否则很可能用户在使用时传进来错误的false参数,从而造成内存管理混乱。

    不论什么类的析构函数编译后签名都变成统一的protected virtual void Finalize(), 这是编译器在后台做的手脚。GC通过Finalize方法来在回收对象前尝试释放资源并进行其他清理操作。有了Finalize方法的保护,即使用户不小心忘记调用Dispose方法,GC在自动调用Finalize时也会正常的执行资源回收,防止泄露发生。

    整理一份干净的for reusing:

class MyDispose : System.IDisposable

{

     private bool disposed = false;

 

     #region IDisposable 成员

     public void Dispose()

     {

         Dispose(true);

         GC.SuppressFinalize(this);

     }

     #endregion

 

     protected virtual void Dispose(bool disposing)

     {

         if (disposed)

              return;

         if (disposing)

         {

              // TODO: 在这里释放托管资源

         }

 

         // TODO: 在这里释放非托管资源

         disposed = true;

     }

 

     ~MyDispose()

     {

         Dispose(false);

     }

}

 

参考:

C# 中的Finalize 和Dispose(bool disposing)和Dispose()

IDisposable.Dispose Method

Implementing a Dispose Method

  评论这张
 
阅读(7436)| 评论(0)

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018