溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

C# 中構(gòu)造函數(shù)與析構(gòu)函數(shù)(二)

發(fā)布時(shí)間:2020-06-20 03:20:46 來源:網(wǎng)絡(luò) 閱讀:799 作者:任永娟2011 欄目:編程語(yǔ)言

(二)析構(gòu)函數(shù)

析構(gòu)函數(shù)

· 不能在結(jié)構(gòu)中定義析構(gòu)函數(shù)。只能對(duì)類使用析構(gòu)函數(shù)。

· 一個(gè)類只能有一個(gè)析構(gòu)函數(shù)。

· 無法繼承或重載析構(gòu)函數(shù)。

· 無法調(diào)用析構(gòu)函數(shù)。它們是被自動(dòng)調(diào)用的。

· 析構(gòu)函數(shù)既沒有修飾符,也沒有參數(shù)。

析構(gòu)函數(shù)(destructor) 與構(gòu)造函數(shù)相反,當(dāng)對(duì)象脫離其作用域時(shí)(例如對(duì)象所在的函數(shù)已調(diào)用完畢),系統(tǒng)自動(dòng)執(zhí)行析構(gòu)函數(shù)。析構(gòu)函數(shù)往往用來做清理善后的工作(例如在建立對(duì)象時(shí)用new開辟了一片內(nèi)存空間,應(yīng)在退出前在析構(gòu)函數(shù)中用delete釋放)。


C++語(yǔ)言為例,析構(gòu)函數(shù)名也應(yīng)與類名相同,只是在函數(shù)名前面加一個(gè)波浪符~,例如~stud( ),以區(qū)別于構(gòu)造函數(shù)。它不能帶任何參數(shù),也沒有返回值(包括void類型)。只能有一個(gè)析構(gòu)函數(shù),不能重載。如果用戶沒有編寫析構(gòu)函數(shù),編譯系統(tǒng)會(huì)自動(dòng)生成一個(gè)缺省的析構(gòu)函數(shù),它也不進(jìn)行任何操作。所以許多簡(jiǎn)單的類中沒有用顯式的析構(gòu)函數(shù)。

解構(gòu)器

我們知道,解構(gòu)器被用來清除類的事例。當(dāng)我們?cè)?/span>C#中使用解構(gòu)器是,我們必須記住以下幾點(diǎn):

一個(gè)類只能有一個(gè)解構(gòu)器。
解構(gòu)器不能被繼承或重載。
解構(gòu)器不能被調(diào)用。他們是自動(dòng)被(編譯器)調(diào)用的。
解構(gòu)器不能帶修飾或參數(shù)。
下面是類MyClass解構(gòu)器的一個(gè)聲明:

 

~ Class()
{
// Cleaning up code goes here
}

 

程序員不能控制解構(gòu)器何時(shí)將被執(zhí)行因?yàn)檫@是由垃圾收集器決定的。垃圾收集器檢查不在被應(yīng)用程序使用的對(duì)象。它認(rèn)為這些條件是符合清楚的并且收回它們的內(nèi)存。解構(gòu)器也在程序退出時(shí)被調(diào)用。當(dāng)解構(gòu)器執(zhí)行時(shí)其背后所發(fā)生的那一幕是解構(gòu)器隱式調(diào)用對(duì)象基類的Object.Finalize方法。因此上述解構(gòu)器代碼被隱含轉(zhuǎn)化成:

 

protected override void Finalize()
{
try
{
// Cleaning up .
}
finally
{
base.Finalize();
}
}

現(xiàn)在,讓我們看一個(gè)解構(gòu)器怎樣被調(diào)用的例子。我們有三個(gè)類A,BC 。B派生自A,C派生自B。每個(gè)類有它們自己的構(gòu)造器和解構(gòu)。在類Appmain函數(shù)中,我們創(chuàng)建C的對(duì)象。

 

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)造器將會(huì)被執(zhí)行并且程序會(huì)等待用戶按‘enter’。當(dāng)這個(gè)發(fā)生,我們把類C的對(duì)象置為null.但解構(gòu)器沒有被執(zhí)行..?。???正像我們所說的,程序員無法控制解構(gòu)器何時(shí)被執(zhí)行因?yàn)檫@是由垃圾搜集器決定的。但程序退出時(shí)解構(gòu)器被調(diào)用了。你能通過重定向程序的o/p到文本文件來檢查這個(gè)。我將它輸出在這里。注意到基類的解構(gòu)器被調(diào)用了,因?yàn)樵诒澈?/span>base.Finalize()被調(diào)用了。

 

Creating A
Creating B
Creating C
Object Created
Press enter to Destroy it
Destroying C
Destroying B
Destroying A
 
所以,如果一旦你使用完對(duì)象你就想調(diào)用解構(gòu)器,你該怎么做?有兩個(gè)方法:

調(diào)用垃圾搜集器來清理。

實(shí)現(xiàn)IDisposableDispose方法。

調(diào)用垃圾搜集器

你能通過調(diào)用GC.Collect方法強(qiáng)制垃圾搜集器來清理內(nèi)存,但在大多數(shù)情況下,這應(yīng)該避免因?yàn)樗鼤?huì)導(dǎo)致性能問題。在上面的程序中,在GC.Collect()處移除注釋。編譯并運(yùn)行它?,F(xiàn)在,你能看到解構(gòu)器在控制臺(tái)中被執(zhí)行了。

 

實(shí)現(xiàn)IDisposable接口

 

IDisposable 接口包括僅有的一個(gè)公共方法,其聲明為void Dispose()。我們能實(shí)現(xiàn)這個(gè)方法來關(guān)閉或釋放非托管資源如實(shí)現(xiàn)了這個(gè)接口的類事例所控制的文件,流,和句柄等。這個(gè)方法被用做所有任務(wù)聯(lián)合對(duì)象的資源釋放。當(dāng)實(shí)現(xiàn)了這個(gè)方法,對(duì)象必須尋求確保所有擁有的資源被繼承結(jié)構(gòu)中關(guān)聯(lián)的資源也釋放(不能把握,翻不出來)。

 

class MyClass:IDisposable
{
public void Dispose()
{
//implementation
}
}

當(dāng)我們實(shí)現(xiàn)了IDisposable接口時(shí),我們需要規(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è)方法中。這個(gè)方法被解構(gòu)器和IDisposable.Dispose()兩著調(diào)用。我們應(yīng)該注意Dispose(bool)沒有在任何地方被調(diào)用除了在IDisposable.Dispose()和解構(gòu)器中。

當(dāng)一個(gè)客戶調(diào)用IDisposable.Dispose()時(shí),客戶特意地想要清理托管的和非托管資源,并且因此完成清理工作。有一件你必須注意的事情是我們?cè)谇謇碣Y源之后立即調(diào)用了GC.SupressFinalize(this)。這個(gè)方法通知垃圾搜集器不需要調(diào)用解構(gòu)器,因?yàn)槲覀円呀?jīng)做了清理。

注意上面的例子,解構(gòu)器使用參數(shù)false調(diào)用Dispose。這里,我們確信垃圾搜集器搜集了托管資源。我們僅僅做非托管資源的清理。

結(jié)論

盡管如此我們花費(fèi)一些時(shí)間實(shí)現(xiàn)IDisposable接口,如果客戶不能合適地調(diào)用它們會(huì)怎樣?為此C#有一個(gè)酷的解決方案。‘using’代碼塊。它看起來像這樣:

using (MyClass objCls =new MyClass())
{

}
 
當(dāng)控制從using塊通過成功運(yùn)行到結(jié)束或者拋出異常退出時(shí),MyClassIDispose.Dispose()將會(huì)被執(zhí)行。記住你例示的對(duì)象必須實(shí)現(xiàn)System.IDisposable接口。using語(yǔ)句定義了哪個(gè)對(duì)象將被清除的一個(gè)范圍。

注:
構(gòu)造函數(shù)與析構(gòu)函數(shù)的區(qū)別:
構(gòu)造函數(shù)和析構(gòu)函數(shù)是在類體中說明的兩種特殊的成員函數(shù)。
構(gòu)造函數(shù)的功能是在創(chuàng)建對(duì)象時(shí),使用給定的值來將對(duì)象初始化。
析構(gòu)函數(shù)的功能是用來釋放一個(gè)對(duì)象的。在對(duì)象刪除前,用它來做一些清理工作,它與構(gòu)造函數(shù)的功能正好相反。

向AI問一下細(xì)節(jié)
AI