1.對象的析構函數與Finalize方法
與C++類似,C#允許程序員為類定義一個”析構函數“:
class MyClass { ~MyClass() //析構函數 { //編寫釋放非托管的資源 } }
上面的代碼編譯后,可以看到:
這里調用了Object類的Finalize方法,這個方法里面是空的,什么也沒有。
與構造函數類似,子類的析構函數會自動調用基類的析構函數,由此不斷上溯,到最頂層的Object。上面顯示了基類的析構函數是在finally里面執行的,這意味着銷毀對象是先完成子類的清理工作,在完成基類的清理工作。如果基類沒有定義析構函數,則跳過繼續向上搜索。當CLR的GC要回收一個定義了析構函數的對象時,它會自動調用Finalize方法,而且調用Finalize方法的時機是不可控的,最好合適的方法就是讓程序員主動以完全可控的方式去釋放非托管的資源(例如文件句柄,數據庫連接)。為此,.NET提供了IDisposable。
IDisposable接口只定義了一個Dispose方法,任何一個希望"手動"回收的非托管資源的類都應該實現該接口。
public interface IDisposable {void Dispose();},因為CLR認為這個接口就是一般的接口,所以不會主動調用。這需要程序員去調用。為了避免資源泄漏,可以這樣:
public class MyClass:IDisposable { ~MyClass() { Dispose(); } public void Dispose() { // } }
Dispose方法應該允許被調用多次而不能引發異常。可以給出比較安全的代碼框架:
MyClass obj = new MyClass(); try { //使用obj對象 } finally { IDisposable disposable = obj as IDisposable; if (obj != null) { obj.Dispose();//是否資源 } }
C#提供了using關鍵來簡化上述代碼。using(MyClass obj=new MyClass()){//使用obj}
類的析構函數專用於清理非托管的資源,只有類需要提供一個在應用程序里面可隨時調用的“顯式”清理資源的功能時,才需要實現IDisposable,然而CLR的GC不會自動調用對象的Dispose()方法,只會調用Finalize方法(也就在析構函數里面)
IDisposable編程模式:
public class MyClass : IDisposable { ~MyClass() { Dispose(); } public void Dispose() { Dispose(true);//這樣會釋放所有的資源 GC.SuppressFinalize(this);//不需要再調用本對象的Finalize方法 } protected virtual void Dispose(bool disposing) { if (disposing) { //清理托管資源 } //清理非托管資源 } }
讀書筆記《.NET4.0面向對象編程漫談》作者:金旭亮老師