为类同时实现IDisposable和析构器

博客介绍了释放非托管代码资源的两种方法,一是运行时强迫执行析构器,但执行时间不确定;二是通过IDisposable接口的Dispose()方法决定释放时间。建议同时实现这两种机制,还给出了实现示例,并说明了相关方法调用要点及注意事项。

有两个可选的方法来释放非托管代码所占用的资源
1:运行时强迫执行析构器,但是你无法确定执行的时间,这是由垃圾收集器的工作原理所决定的。
2:IDisposable接口提供了一个机制,它允许类的用户通过调用Dispose()方法来决定何时释放资源。

一般来说,最好的方法是同时实现这两个机制,因为这样就可以互相克服各自的缺点。假如大多数的程序员都可以正确的调用Dispose()方法,你就可以实现IDisposable接口,同时要考虑到如果没有正确调用Dispose()方法,保证代码安全就需要提供一个析构器。下面是一个同时实现IDisposable和析构器例子。

None.gifusing System;
None.gif
ExpandedBlockStart.gifContractedBlock.gif
namespace Chengbo dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
class MyClass dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public static void Main() dot.gif{
InBlock.gif            ResourceHolder r1 
= new ResourceHolder();
InBlock.gif            Console.WriteLine(
"IDisposable");
InBlock.gif            r1.Dispose();
InBlock.gif            ResourceHolder r2 
= new ResourceHolder();
InBlock.gif            Console.WriteLine(
"Garbage Collector");
InBlock.gif            GC.Collect();
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif    
ExpandedSubBlockStart.gifContractedSubBlock.gif    
public class ResourceHolder : IDisposable dot.gif{
InBlock.gif        
private bool isDisposed;
InBlock.gif        
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public void Dispose() dot.gif{
InBlock.gif            Dispose(
true);
InBlock.gif            
//请求系统不要调用指定对象的完成器方法。
InBlock.gif
            GC.SuppressFinalize(this);
ExpandedSubBlockEnd.gif        }

InBlock.gif        
ExpandedSubBlockStart.gifContractedSubBlock.gif        
protected virtual void Dispose(bool disposing) dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
if(!isDisposed) dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif                
if(disposing) dot.gif{
InBlock.gif                    Console.WriteLine(
"Dispose the manage objectdot.gif");
ExpandedSubBlockEnd.gif                }

InBlock.gif                Console.WriteLine(
"Dispose the unmanage objectdot.gif");
ExpandedSubBlockEnd.gif            }

InBlock.gif            isDisposed 
= true;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
ExpandedSubBlockStart.gifContractedSubBlock.gif        
~ResourceHolder() dot.gif{
InBlock.gif            Dispose(
false);
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

可以看到,Dispose()有个受保护的重载方法,它接受一个bool参数,执行所有的清理工作,同时被析构器和IDisposable.Dispose()调用。这样做的要点就是保证所有的清理代码都在一处。

传递给Dispose(bool)方法的参数指出到底是IDisposable.Dispose()还是析构器在调用Dispose(bool)方法。在代码的其它任何地方都不能调用Dispose(bool)方法,因为:
1:如果用户调用IDisposable.Dispose(),那么所有的托管和与对象有关的非托管资源都会被清除。
2:如果析构器被调用,那么所有的资源依旧需要清除。但是在这种情况下,我们知道析构器是被垃圾收集器调用的,因为我们不再确定其它托管对象的状态,所以我们并不应该尝试访问它们。我们最好是清除已知的非托管资源,同时希望所有引用的托管对象包含他们自己的析构器来执行自身的垃圾收集。

成员变量isDisposed表示对象是否已经被Dispose,从而保证我们不多次尝试Dispose它。这个简单的方法不是线程安全的(thread-safe),我们只能期望调用者确定调用时只有一个线程。要求用户强制同步是一个合理的假定,这在.NET类库里再三被用到(比如在Collection类中)。

最后,IDisposable.Dispose()调用了System.GC.SuppressFinalize()方法。GC是一个被设计成描述垃圾收集器的类,SuppressFinalize()方法告诉垃圾收集器不需要调用析构器。因为执行Dispose()后就已经做了需要的所有清除工作,没有任何事留给析构器去做了。调用SuppressFinalize()方法也就是说垃圾收集器就像根本就没析构器一样的处理这个类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值