BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / dot-net / #3728同步于 2012/5/19
该镜像源已超过 30 天没有更新,可能在源站已被删除。
dotNET机器人发帖

[问题]C#中dispose方法

liuke20008
2012/5/19镜像同步5 回复
C#中dispose的标准模式是写两个dispose方法,一个是公有的不带参数的dispose()方法,一个是私有的带布尔参数的dispose(bool disposing)方法.一个例子如下: public class DisposeTest:IDisposable { public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { if(!disposed) { if(disposing) { // 释放托管资源 } // 释放非托管资源 } disposed = true; } ~DisposeTest() { Dispose(false); } } 我的疑问在于Dispose(true)和Dispose(false)的区别上。我查阅过很多资料,所有的资料上都如下所述“当用户显示调用Dispose()方法时,要清理托管资源和非托管资源,并且调用GC.SuppressFinalize方法阻止垃圾收集器再次调用Finalise方法;当用户没有调用Dispose()方法,而是由垃圾收集器调用Finalize方法时,应该只释放非托管资源,而不应释放托管资源。因为假若在Finalize方法中引用另一个托管对象时,我们无法确定此时该托管对象的状态如何(是否已被回收)。”我非常不明白的是为什么Finalize方法中不能含有托管类型的引用,按照他们说的,“无法确定此时该托管对象的状态如何”,那么对于其他方法而言,它们里面为什么可以含有其他托管类型的引用???
订阅后,新回复会通过你的通知中心匿名送达。
5 条回复
ahomer机器人#1 · 2012/5/20
你的这段话,可以理解为,除非为了手动释放"非托管资源",否则没必要自己写释放资源的方法,由GC自己判断就行了。 由于GC自己释放托管资源的时候,会调用Finalize。 ~DisposeTest() { } C#的这个所谓析构函数,就是Finalized。 你如果在这里也释放托管资源,相当于帮GC做了一点事情,是没必要的。 并且每个对象在某个方法里面被引用,就会导致它的生命期延长。 可以在任何方法调用托管对象,得看有没必要。 手动释放托管对象是没必要的。 如果要释放托管资源,调用GC.Collect()触发垃圾收集就行了。
liuke20008机器人#2 · 2012/5/20
【 在 ahomer 的大作中提到: 】 : 你的这段话,可以理解为,除非为了手动释放"非托管资源",否则没必要自己写释放资源的方法,由GC自己判断就行了。 : 由于GC自己释放托管资源的时候,会调用Finalize。 : ~DisposeTest() : ................... 这是摘自《Csharp高级编程(第6版)》里的一段话,红线标注的是我疑问的地方,它的意思不就是在析构函数里不应该访问托管对象么?
liuke20008机器人#3 · 2012/5/20
【 在 ahomer 的大作中提到: 】 : 你的这段话,可以理解为,除非为了手动释放"非托管资源",否则没必要自己写释放资源的方法,由GC自己判断就行了。 : 由于GC自己释放托管资源的时候,会调用Finalize。 : ~DisposeTest() : ................... 囧,不会发图。还是把原话打上去吧。 “传递给Dispose(bool)的参数表示Dispose(bool)是由析构函数调用还是由IDispose.Dispose()调用——Dispose(bool)不应从代码的其他地方调用,其原因是: 1.如果客户调用IDispose.Dispose(),该客户就指定应清理所有与该对象相关的资源,包括托管资源和非托管的资源; 2.如果调用了析构函数,原则上所有的资源仍需要清理。但是在这种情况下,析构函数必须由垃圾收集器调用,而且不应访问其他托管的对象,因为我们不再能确定它们的状态了。在这种情况下,最好清理已知的未托管资源,希望引用的托管对象还有析构函数,执行自己的清理过程。 ”(打字好累~)
ahomer机器人#4 · 2012/5/20
建议看 <<CLR VIA C#>>(.NET框架设计),其中有一节讲 垃圾收集的原理,你看下.NET的垃圾收集机制先
RayNCC机器人#5 · 2012/7/26
在finilize的时候,是gc在工作,说明已经开始gc了,其他工作都被hold住。而gc回收的顺序是不定的,在finilize里面访问另外一个托管对象,这个对象可能已经被gc掉了