注意:GC最终虽然会释放托管资源,但是GC并不知道或者关心你的Dispose方法。那仅仅是一个我们选择的名字。
GC调用析构函数是一个完美的时机来释放托管资源,我们实现析构函数的功能通过重写Finalize方法。
注意:在C#中,你不能真的去使用重写虚函数的方法去重写Finalize方法。你只能使用像C++的析构函数的语法去编写,编译器会自动对你的代码进行一些改动来实现override终结器方法。(具体可查看MSDN中析构函数一节)
~MyObject()
{
//we're being finalized (i.e.destroyed), call Dispose in case the user forgot to
Dispose(); //<--Warning:subtle bug! Keep reading!
}
但是这有一个Bug。
试想一下,你的GC是在后台线程调用,你对GC的调用时间和对垃圾对象的释放顺序根本无法掌控,很有可能的发生的是,你的对象的某些托管资源已经在调用终结器之前就被释放了,当GC调用终结器时,最终会释放两次托管资源!
public void Dispose()
{
//Free unmanaged resources
Win32.DestroyHandle(this.gdiCursorBitmapStreamFileHandle);
//Free managed resources too
if (this.databaseConnection !=null)
{
this.databaseConnection.Dispose(); //<-- crash, GC already destroyedit
this.databaseConnection =null;
}
if (this.frameBufferImage !=null)
{
this.frameBufferImage.Dispose(); //<-- crash, GC already destroyed it
this.frameBufferImage = null;
}
}
所以你需要做的是让终结器告诉Dispose方法,它不应该再次释放任何托管资源了(因为这些资源很有可能已经被释放了!)
标准的Dispose模式是让Dispose函数和Finalize方法通过调用第三种方法,这个方法有一个bool类型的形参来表示此方法的调用是通过Dispose还是GC调用终结器。在这个方法里实现具体的释放资源代码。
这个第三种方法的命名当然可以随意命名,但是规范的方法签名是:
protected void Dispose(Boolean disposing)
当然,这个参数的名字会让人读不懂什么意思。(很多网上教程都使用这个名字,第一次看很难看懂这个变量的作用)
这个参数也许可以这样写…
protected void Dispose(Boolean itIsSafeToAlsoFreeManagedObjects)
{
//Free unmanaged resources
Win32.DestroyHandle(this.CursorFileBitmapIconServiceHandle);
//Free managed resources too, butonly if I'm being called from Dispose
//(If I'm being called fromFinalize then the objects might not exist
//anymore
if(itIsSafeToAlsoFreeManagedObjects)
{
if (this.databaseConnection !=null)
{
this.databaseConnection.Dispose();
this.databaseConnection =null;
}
if (this.frameBufferImage !=null)
{
this.frameBufferImage.Dispose();
this.frameBufferImage =null;
}
}
}










