·天新网首页·加入收藏·设为首页·网站导航
数码笔记本手机摄像机相机MP3MP4GPS
硬件台式机网络服务器主板CPU硬盘显卡
办公投影打印传真
家电电视影院空调
游戏网游单机动漫
汽车新车购车试驾
下载驱动源码
学院开发设计
考试公务员高考考研
业界互联网通信探索
您现在的位置:天新网 > 软件开发 > .Net开发 > C#
C#基础知识梳理系列十二:终结操作及资源清理
http://www.21tx.com 2012年08月28日 博客园 solan3000

上一页 1 2

第三节 使用Dispose模式

在上面的讨论中,我们知道Finalize方法是受CLR管控的,也就是一个类型的本地资源在什么时候得到清理,我们并不太清楚,有没有一种方法可以让我们对其方便地控制呢?当然有!那就是实现Dispose模式。

接口System.IDisposeable提供了对Dispose模式实现的最佳实践。

public interface IDisposable 
{ 
    void Dispose(); 
}

通过实现这个接口,我们可以方便规范地来管理包装了本地资源的类对象,这个模式起到了双重保险的作用,可以分别清理托管和非托管资源。像TextReader、FileStream、WinForm窗体都实现了这个接口,这里我们推荐MSDN上面的实现方式。我们继续对上面的FileManager类进行改造:

public class FileManager : IDisposable 
    { 
        private bool disposed = false; 
        //非托管资源 
        private IntPtr handle; 
        //托管资源 
        FileStream fs = null; 
        public FileManager() 
        { 
        } 
        ~FileManager() 
        { 
            //GC调用,终结 
            Dispose(false); 
        } 
   
        public void Dispose() 
        { 
            //显示关闭 
            Dispose(true); 
            //通知GC不必再调用Finalize() 
            GC.SuppressFinalize(this); 
        } 
        protected virtual void Dispose(bool disposing) 
        { 
            if (!this.disposed) 
            { 
                if (disposing && fs != null) 
                { 
                    // 释放托管资源 
                    fs.Dispose(); 
                } 
   
                //释放非托管资源 
                //... 
                handle = IntPtr.Zero; 
   
                disposed = true; 
            } 
   
        } 
    }

除了实现接口的Dispose()方法,还创建了一个通用的方法Dispose(bool disposing) ,在此方法内,如果对象已经被清理,则不再做清理工作。有两点要注意:

(1)Dispose()方法内部,传递了一个true值告诉Dispose(bool disposing)方法此次调用是手工调用,接着使用一个静态方法GC.SuppressFinalize(this);告诉垃圾回收器,此对象我已经手工调用清理资源的方法,你不必再调用Finalize()方法了。

(2)~FileManager()方法内是传一个false值告诉Dispose(bool disposing)此对象是通过垃圾回收器清理资源的。

也就是说,对于FileManager对象,如果你手工调用了清理的方法,则会对托管和非托管方法进行清理,如果你忘记了手工调用,垃圾回收器还是会通过调用Finalize()方法对非托管资源进行清理。

第四节 使用using

一般地,对于实现了IDisposeable接口的类型对象,在使用完毕后我会在finally块中调用Dispose方法来释放资源。如下:

FileManager fs = null; 
            try
            { 
                //fs... 
            } 
            finally
            { 
                if (fs != null) 
                { 
                    fs.Dispose(); 
                } 
            }

其实也可以以一种更简洁的方法来实现,那就是使用using语句,如下:

public void Test() 
        { 
            FileManager fs = null; 
            using (fs = new FileManager()) 
            { 
                Console.WriteLine(fs.ToString()); 
            } 
        }

我们来看一下编译器生成的IL是什么样的?

.method public hidebysig instance void  Test() cil managed 
{ 
  // 代码大小       45 (0x2d) 
  .maxstack  2 
  .locals init ([0] class ConsoleApp.Example12.FileManager fs, 
           [1] class ConsoleApp.Example12.FileManager CS$3$0000, 
           [2] bool CS$4$0001) 
  IL_0000:  nop 
  IL_0001:  ldnull 
  IL_0002:  stloc.0 
  IL_0003:  newobj     instance void ConsoleApp.Example12.FileManager::.ctor() 
  IL_0008:  dup 
  IL_0009:  stloc.0 
  IL_000a:  stloc.1 
  .try
  { 
    IL_000b:  nop 
    IL_000c:  ldloc.0 
    IL_000d:  callvirt   instance string [mscorlib]System.Object::ToString() 
    IL_0012:  call       void [mscorlib]System.Console::WriteLine(string) 
    IL_0017:  nop 
    IL_0018:  nop 
    IL_0019:  leave.s    IL_002b 
  }  // end .try 
  finally
  { 
    IL_001b:  ldloc.1 
    IL_001c:  ldnull 
    IL_001d:  ceq 
    IL_001f:  stloc.2 
    IL_0020:  ldloc.2 
    IL_0021:  brtrue.s   IL_002a 
    IL_0023:  ldloc.1 
    IL_0024:  callvirt   instance void [mscorlib]System.IDisposable::Dispose() 
    IL_0029:  nop 
    IL_002a:  endfinally 
  }  // end handler 
  IL_002b:  nop 
  IL_002c:  ret 
} // end of method Code_12::Test

可以看到,编译器对于using语句是按照try…finally块模式来处理,并且在finally块中调用了Dispose方法,与上面我们手工编写的try…finally块代码实现了相同的功能。

在类似的环境中,using语句只能应用于实现了System.IDisposable接口的类型(或值类型)对象。

小 结

本博客文章版权归博客园和solan3000共同所有。

上一篇: C#基础知识梳理系列六:抽象类与接口
下一篇: C#基础知识梳理系列八:定制特性Attribute

上一页 1 2

关于我们 | 联系我们 | 加入我们 | 广告服务 | 投诉意见 | 网站导航
Copyright © 2000-2011 21tx.com, All Rights Reserved.
晨新科技 版权所有 Created by TXSite.net