Idisposable, Finalize和Destructor在C#中的关系

“有什么好的面试题没有?”这句话是最近同事们经常提到的话题。各位同事在每年的这个时候都成了标准的赶场面试官,今年他们最大的困惑就是感觉找新题难。找新题要有些原则,不能只靠智力题,也不能用那些BBS上随处可见的编程题。不过我想对于我的这些老大们应该还不是问题。

恰好,一位同事提到了Idisposable, Finalizer和Destructor在C#中的关系,我想咱还是从最基础的知识巩固一下吧,也算是给很长时间没更新的blog,恢复一下青春。

大家都知道在.NET中,Garbage collector(GC)能够帮助我们自动地清理分配在managed heap上的对象,这个的确有用。但是当我们在设计一个类的时候,如果使用到了非托管的资源,比如说Handle,DB connection等等,这个时候假如我们没有写出适当的逻辑对这些非托管资源进行释放,就会造成Handle Leak等资源泄露问题。那如何是好呢?有人说用“析构函数”怎么样?答案:不行。因为析构函数在C#中的行为是Non-deterministic的。其行为是由GC在某个时候调用的。

既然Destructor是C#用来执行清理操作的机制的话,它是在什么时候被调用呢?这下子Finalize的概念就要出场了。Finalize方法是定义在Object类中的,该方法在当对象不可访问后(没有指向该对象的引用)被自动调用,除非该对象已经使用GC.SuppressFinalize()方法从而免于执行其Finalize方法。这也是为了防止该对象调用了两次Finalize,否则会出现ObjectDisposedException异常哦。说道这里,真相揭晓:在C#中Finalize就是以Destructor的形式体现出来的。Finalize方法本身不能在C#中被调用或者重写。

说白了,Finalize方法是在用户忘记显示地释放系统资源的情况下,GC在调用Collector方法收回内存前,被CLR执行的一段“保险”代码。在这时,我们只需要清理那些非托管资源就好了,因为对象中的其他托管资源会在垃圾回收时被CLR处理。

最后,如果我们想更可控释放对象的资源该怎么办呢?对了,请事先接口IDisposable中的void Dispose()方法。它大多数情况下是用户在最后一次使用某对象后被调用。此时我们既要释放该对象所引用的其他对象的资源,也要同时释放其自身调用的非托管资源。如果该对象还是一个派生类的话,他还要负责释放基类的资源。最后别忘了在Dispose时调用GC.SuppressFinalize(this)方法,告诉CLR不要在执行Finalize方法了。

参考:

posted on 2007-01-09 15:25  晓崔  阅读(653)  评论(0)    收藏  举报

导航