(二)析構(gòu)函數(shù)
成都創(chuàng)新互聯(lián)公司服務(wù)項目包括東光網(wǎng)站建設(shè)、東光網(wǎng)站制作、東光網(wǎng)頁制作以及東光網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,東光網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到東光省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
析構(gòu)函數(shù)
·不能在結(jié)構(gòu)中定義析構(gòu)函數(shù)。只能對類使用析構(gòu)函數(shù)。
·一個類只能有一個析構(gòu)函數(shù)。
·無法繼承或重載析構(gòu)函數(shù)。
·無法調(diào)用析構(gòu)函數(shù)。它們是被自動調(diào)用的。
·析構(gòu)函數(shù)既沒有修飾符,也沒有參數(shù)。
析構(gòu)函數(shù)(destructor)與構(gòu)造函數(shù)相反,當(dāng)對象脫離其作用域時(例如對象所在的函數(shù)已調(diào)用完畢),系統(tǒng)自動執(zhí)行析構(gòu)函數(shù)。析構(gòu)函數(shù)往往用來做“清理善后”的工作(例如在建立對象時用new開辟了一片內(nèi)存空間,應(yīng)在退出前在析構(gòu)函數(shù)中用delete釋放)。
以C++語言為例,析構(gòu)函數(shù)名也應(yīng)與類名相同,只是在函數(shù)名前面加一個波浪符~,例如~stud( ),以區(qū)別于構(gòu)造函數(shù)。它不能帶任何參數(shù),也沒有返回值(包括void類型)。只能有一個析構(gòu)函數(shù),不能重載。如果用戶沒有編寫析構(gòu)函數(shù),編譯系統(tǒng)會自動生成一個缺省的析構(gòu)函數(shù),它也不進(jìn)行任何操作。所以許多簡單的類中沒有用顯式的析構(gòu)函數(shù)。
解構(gòu)器
我們知道,‘解構(gòu)器’被用來清除類的事例。當(dāng)我們在C#中使用解構(gòu)器是,我們必須記住以下幾點:
一個類只能有一個解構(gòu)器。
解構(gòu)器不能被繼承或重載。
解構(gòu)器不能被調(diào)用。他們是自動被(編譯器)調(diào)用的。
解構(gòu)器不能帶修飾或參數(shù)。
下面是類MyClass解構(gòu)器的一個聲明:
~ Class()
{
// Cleaning up code goes here
}
程序員不能控制解構(gòu)器何時將被執(zhí)行因為這是由垃圾收集器決定的。垃圾收集器檢查不在被應(yīng)用程序使用的對象。它認(rèn)為這些條件是符合清楚的并且收回它們的內(nèi)存。解構(gòu)器也在程序退出時被調(diào)用。當(dāng)解構(gòu)器執(zhí)行時其背后所發(fā)生的那一幕是解構(gòu)器隱式調(diào)用對象基類的Object.Finalize方法。因此上述解構(gòu)器代碼被隱含轉(zhuǎn)化成:
protected override void Finalize()
{
try
{
// Cleaning up .
}
finally
{
base.Finalize();
}
}
現(xiàn)在,讓我們看一個解構(gòu)器怎樣被調(diào)用的例子。我們有三個類A,B和C。B派生自A,C派生自B。每個類有它們自己的構(gòu)造器和解構(gòu)。在類App的main函數(shù)中,我們創(chuàng)建C的對象。
using System;
class A
{
public A()
{
Console.WriteLine("Creating A");
}
~A()
{
Console.WriteLine("Destroying A");
}
}
class B:A
{
public B()
{
Console.WriteLine("Creating B");
}
~B()
{
Console.WriteLine("Destroying B");
}
}
class C:B
{
public C()
{
Console.WriteLine("Creating C");
}
~C()
{
Console.WriteLine("Destroying C");
}
}
class App
{
public static void Main()
{
C c=new C();
Console.WriteLine("Object Created ");
Console.WriteLine("Press enter to Destroy it");
Console.ReadLine();
c=null;
//GC.Collect();
Console.Read();
}
}
正如我們預(yù)料的,基類的構(gòu)造器將會被執(zhí)行并且程序會等待用戶按‘enter’。當(dāng)這個發(fā)生,我們把類C的對象置為null.但解構(gòu)器沒有被執(zhí)行..?。???正像我們所說的,程序員無法控制解構(gòu)器何時被執(zhí)行因為這是由垃圾搜集器決定的。但程序退出時解構(gòu)器被調(diào)用了。你能通過重定向程序的o/p到文本文件來檢查這個。我將它輸出在這里。注意到基類的解構(gòu)器被調(diào)用了,因為在背后base.Finalize()被調(diào)用了。
Creating A
Creating B
Creating C
Object Created
Press enter to Destroy it
Destroying C
Destroying B
Destroying A
所以,如果一旦你使用完對象你就想調(diào)用解構(gòu)器,你該怎么做?有兩個方法:
調(diào)用垃圾搜集器來清理。
實現(xiàn)IDisposable的Dispose方法。
調(diào)用垃圾搜集器
你能通過調(diào)用GC.Collect方法強制垃圾搜集器來清理內(nèi)存,但在大多數(shù)情況下,這應(yīng)該避免因為它會導(dǎo)致性能問題。在上面的程序中,在GC.Collect()處移除注釋。編譯并運行它。現(xiàn)在,你能看到解構(gòu)器在控制臺中被執(zhí)行了。
實現(xiàn)IDisposable接口
IDisposable接口包括僅有的一個公共方法,其聲明為void Dispose()。我們能實現(xiàn)這個方法來關(guān)閉或釋放非托管資源如實現(xiàn)了這個接口的類事例所控制的文件,流,和句柄等。這個方法被用做所有任務(wù)聯(lián)合對象的資源釋放。當(dāng)實現(xiàn)了這個方法,對象必須尋求確保所有擁有的資源被繼承結(jié)構(gòu)中關(guān)聯(lián)的資源也釋放(不能把握,翻不出來)。
class MyClass:IDisposable
{
public void Dispose()
{
//implementation
}
}
當(dāng)我們實現(xiàn)了IDisposable接口時,我們需要規(guī)則來確保Dispose被適當(dāng)?shù)卣{(diào)用。
聯(lián)合使用解構(gòu)器和IDisposable接口
Public class MyClass:IDisposable
{
private bool IsDisposed=false;
public void Dispose()
{
Dispose(true);
GC.SupressFinalize(this);
}
protected void Dispose(bool Diposing)
{
if(!IsDisposed)
{
if(Disposing)
{
//Clean Up managed resources
}
//Clean up unmanaged resources
}
IsDisposed=true;
}
~MyClass()
{
Dispose(false);
}
}
在這里重載了Dispose(bool)來做清理工作,并且所有的清理代碼都僅寫在這個方法中。這個方法被解構(gòu)器和IDisposable.Dispose()兩著調(diào)用。我們應(yīng)該注意Dispose(bool)沒有在任何地方被調(diào)用除了在IDisposable.Dispose()和解構(gòu)器中。
當(dāng)一個客戶調(diào)用IDisposable.Dispose()時,客戶特意地想要清理托管的和非托管資源,并且因此完成清理工作。有一件你必須注意的事情是我們在清理資源之后立即調(diào)用了GC.SupressFinalize(this)。這個方法通知垃圾搜集器不需要調(diào)用解構(gòu)器,因為我們已經(jīng)做了清理。
注意上面的例子,解構(gòu)器使用參數(shù)false調(diào)用Dispose。這里,我們確信垃圾搜集器搜集了托管資源。我們僅僅做非托管資源的清理。
結(jié)論
盡管如此我們花費一些時間實現(xiàn)IDisposable接口,如果客戶不能合適地調(diào)用它們會怎樣?為此C#有一個酷的解決方案。‘using’代碼塊。它看起來像這樣:
using (MyClass objCls =new MyClass())
{
}
當(dāng)控制從using塊通過成功運行到結(jié)束或者拋出異常退出時,MyClass的IDispose.Dispose()將會被執(zhí)行。記住你例示的對象必須實現(xiàn)System.IDisposable接口。using語句定義了哪個對象將被清除的一個范圍。
注:
構(gòu)造函數(shù)與析構(gòu)函數(shù)的區(qū)別:
構(gòu)造函數(shù)和析構(gòu)函數(shù)是在類體中說明的兩種特殊的成員函數(shù)。
構(gòu)造函數(shù)的功能是在創(chuàng)建對象時,使用給定的值來將對象初始化。
析構(gòu)函數(shù)的功能是用來釋放一個對象的。在對象刪除前,用它來做一些清理工作,它與構(gòu)造函數(shù)的功能正好相反。