Finalize 和Dispose(bool disposing)和 Dispose() 的相同點(diǎn):
這三者都是為了釋放非托管資源服務(wù)的.
Finalize 和 Dispose() 和Dispose(bool disposing)的不同點(diǎn):
- Finalize是CRL提供的一個(gè)機(jī)制, 它保證如果一個(gè)類實(shí)現(xiàn)了Finalize方法,那么當(dāng)該類對(duì)象被垃圾回收時(shí),垃圾回收器會(huì)調(diào)用Finalize方法.而該類的開發(fā)者就必須在Finalize方法中處理 非托管資源的釋放. 但是什么時(shí)候會(huì)調(diào)用Finalize由垃圾回收器決定,該類對(duì)象的使用者(客戶)無(wú)法控制.從而無(wú)法及時(shí)釋放掉寶貴的非托管資源.由于非托管資源是比較寶貴了,所以這樣會(huì)降低性能.
- Dispose(bool disposing)不是CRL提供的一個(gè)機(jī)制, 而僅僅是一個(gè)設(shè)計(jì)模式(作為一個(gè)IDisposable接口的方法),它的目的是讓供類對(duì)象的使用者(客戶)在使用完類對(duì)象后,可以及時(shí)手動(dòng)調(diào)用非托管資源的釋放,無(wú)需等到該類對(duì)象被垃圾回收那個(gè)時(shí)間點(diǎn).這樣類的開發(fā)者就只需把原先寫在Finalize的釋放非托管資源的代碼,移植到Dispose(bool disposing)中. 而在Finalize中只要簡(jiǎn)單的調(diào)用 "Dispose(false)"(為什么傳遞false后面解釋)就可以了.
這個(gè)時(shí)候我們可能比較疑惑,為什么還需要一個(gè)Dispose()方法?難道只有一個(gè)Dispose(bool disposing)或者只有一個(gè)Dispose()不可以嗎?
答案是:
只有一個(gè)Dispose()不可以. 為什么呢?因?yàn)槿绻挥幸粋€(gè)Dispose()而沒(méi)有Dispose(bool disposing)方法.那么在處理實(shí)現(xiàn)非托管資源釋放的代碼中無(wú)法判斷該方法是客戶調(diào)用的還是垃圾回收器通過(guò)Finalize調(diào)用的.無(wú)法實(shí)現(xiàn) 判斷如果是客戶手動(dòng)調(diào)用,那么就不希望垃圾回收器再調(diào)用Finalize()(調(diào)用GC.SupperFinalize方法).另一個(gè)可能的原因(:我們知道如果是垃圾回收器通過(guò)Finalize調(diào)用的,那么在釋放代碼中我們可能還會(huì)引用其他一些托管對(duì)象,而此時(shí)這些托管對(duì)象可能已經(jīng)被垃圾回收了, 這樣會(huì)導(dǎo)致無(wú)法預(yù)知的執(zhí)行結(jié)果(千萬(wàn)不要在Finalize中引用其他的托管對(duì)象).
所以確實(shí)需要一個(gè)bool disposing參數(shù), 但是如果只有一個(gè)Dispose(bool disposing),那么對(duì)于客戶來(lái)說(shuō),就有一個(gè)很滑稽要求,Dispose(false)已經(jīng)被Finalize使用了,必須要求客戶以Dispose(true)方式調(diào)用,但是誰(shuí)又能保證客戶不會(huì)以Dispose(false)方式調(diào)用呢?所以這里采用了一中設(shè)計(jì)模式:重載 把Dispose(bool disposing)實(shí)現(xiàn)為 protected, 而Dispose()實(shí)現(xiàn)為Public,那么這樣就保證了客戶只能調(diào)用Dispose()(內(nèi)部調(diào)用Dispose(true)//說(shuō)明是客戶的直接調(diào)用),客戶無(wú)法調(diào)用Dispose(bool disposing).
范例如下:
public class BaseResource: IDisposable
{
//析構(gòu)函數(shù)自動(dòng)生成 Finalize 方法和對(duì)基類的 Finalize 方法的調(diào)用.默認(rèn)情況下,一個(gè)類是沒(méi)有析構(gòu)函數(shù)的,也就是說(shuō),對(duì)象被垃圾回收時(shí)不會(huì)被調(diào)用Finalize方法
~BaseResource()
{
// 為了保持代碼的可讀性性和可維護(hù)性,千萬(wàn)不要在這里寫釋放非托管資源的代碼
// 必須以Dispose(false)方式調(diào)用,以false告訴Dispose(bool disposing)函數(shù)是從垃圾回收器在調(diào)用Finalize時(shí)調(diào)用的
Dispose(false);
}
// 無(wú)法被客戶直接調(diào)用
// 如果 disposing 是 true, 那么這個(gè)方法是被客戶直接調(diào)用的,那么托管的,和非托管的資源都可以釋放
// 如果 disposing 是 false, 那么函數(shù)是從垃圾回收器在調(diào)用Finalize時(shí)調(diào)用的,此時(shí)不應(yīng)當(dāng)引用其他托管對(duì)象所以,只能釋放非托管資源
protected virtual void Dispose(bool disposing)
{
// 那么這個(gè)方法是被客戶直接調(diào)用的,那么托管的,和非托管的資源都可以釋放
if(disposing)
{
// 釋放 托管資源
OtherManagedObject.Dispose();
}
//釋放非托管資源
DoUnManagedObjectDispose();
// 那么這個(gè)方法是被客戶直接調(diào)用的,告訴垃圾回收器從Finalization隊(duì)列中清除自己,從而阻止垃圾回收器調(diào)用Finalize方法.
if(disposing)
GC.SuppressFinalize(this);
}
//可以被客戶直接調(diào)用
public void Dispose()
{
//必須以Dispose(true)方式調(diào)用,以true告訴Dispose(bool disposing)函數(shù)是被客戶直接調(diào)用的
Dispose(true);
}
}
上面的范例達(dá)到的目的:
1/ 如果客戶沒(méi)有調(diào)用Dispose(),未能及時(shí)釋放托管和非托管資源,那么在垃圾回收時(shí),還有機(jī)會(huì)執(zhí)行Finalize(),釋放非托管資源,但是造成了非托管資源的未及時(shí)釋放的空閑浪費(fèi)
2/ 如果客戶調(diào)用了Dispose(),就能及時(shí)釋放了托管和非托管資源,那么該對(duì)象被垃圾回收時(shí),不回執(zhí)行Finalize(),提高了非托管資源的使用效率并提升了系統(tǒng)性能
可以參考SqlConnection對(duì)象的New, Open, Close(內(nèi)部調(diào)用Dispose())的使用經(jīng)歷可以加深對(duì)他們的理解.謝謝!