safehandle 和析构函数
safehandle?是一種析構(gòu)機制,她和析構(gòu)函數(shù)有什么分別。
?
首先要理解析構(gòu)函數(shù)。析構(gòu)函數(shù)在.net中是沒有順序的,因此你不能假定另一個對象的析構(gòu)函數(shù)在你之后運行,哪怕它是你的成員!如果你的成員也有析構(gòu)函數(shù),那么你能做什么,什么不應(yīng)該做?
第一,在析構(gòu)函數(shù)運行時,你不應(yīng)該假設(shè)它沒清理資源,而去試圖清理它。合理的做法是它應(yīng)該自己實現(xiàn)dispose模式,你在dispose(true)段落可以調(diào)用它的dispose()函數(shù).因為dispose是可多次重入的,因此不會有問題。如果它沒有,那就別去理他,因為它的析構(gòu)函數(shù)會釋放它的非托管資源。這樣的好處是,我可以分別控制每一個實現(xiàn)dispose模式的對象成員的控制時機,而dispose(false)也就是析構(gòu)函數(shù),能夠作為防御性代碼,幫你把忘記的“非托管”資源清理掉。
第二,一個實現(xiàn)了dispose的.net對象,外部應(yīng)該怎樣看它?不應(yīng)該把它所控制的資源看作非托管資源,既然他實現(xiàn)了dispose,也就是“有自行管理”的,因此只需要在dispose(true)段落調(diào)用它的dispose函數(shù),讓其在顯式清理實際時產(chǎn)生效果便可。這是我對dispose模式的理解。dispose模式分兩類資源,一類是托管,一類是非托管。托管和非托管并不是純粹站在.net角度出發(fā),而是應(yīng)該理解為“自己管理”和“其他對象管理”的差別。你的對象自己打開文件,就自己負責關(guān)閉,而其他對象,包括成員對象,他們控制的資源就由他們控制,在當前立場上看,都是“受托管的”。
第三,你的對象的 dispose 應(yīng)該被顯式調(diào)用(也就是最外層對象)!這個是dispose模式的關(guān)鍵,因為析構(gòu)函數(shù)只是負責自身非托管資源的釋放,它沒有參與整套資源管理流程。如果你不顯式調(diào)用(或者另外編寫代碼),清理流程是不可能正確執(zhí)行的。
第四。為何析構(gòu)函數(shù)不負責dispose的所有內(nèi)容,首先是析構(gòu)順序的不確定性,而資源管控流程需要順序;其次,析構(gòu)函數(shù)沒有明確的調(diào)用時機,而dispose可以在任意時刻調(diào)用。
?
然后是safehandle,safehandle據(jù)說有經(jīng)過優(yōu)化,但是它也不會搶先在析構(gòu)函數(shù)階段運行,在我測試中是這種情況。因此,我不知道優(yōu)化在那里了。只是添加了一種模式,比析構(gòu)函數(shù)更舵控制,畢竟是外部獨立的類,而且系統(tǒng)已經(jīng)針對多種資源提供了恰當?shù)淖宇?#xff0c;可惜沒有針對com對象資源。
?
總的來說,最佳實踐是:
1.如果safehandle子類有的系統(tǒng)資源,如句柄,非托管內(nèi)存等等,用safehandle?模式。
2.如果子成員正確實現(xiàn)了dispose,把它視為托管資源,在dispose(true)中調(diào)用。
3.如果子成員沒有實現(xiàn)dispose,但是控制了相關(guān)資源,也就是你要負責子對象相關(guān)資源的顯式控制,千萬別用析構(gòu)函數(shù)清理,因為析構(gòu)函數(shù)階段,子成員可能已經(jīng)把它關(guān)聯(lián)的資源給釋放掉了(未必以正確的方式,只是對資源失去控制力),你無法再清理。因為GC對任意對象的析構(gòu)函數(shù)調(diào)用順序是不確定的。(這一狀況只能要求你在編程階段正確調(diào)用dispose,而絕不能遺忘調(diào)用,否則就有資源泄漏。com for .net就是如此設(shè)計的)
4.一般情況,dispose(true)負責對象鏈的清理流程,dispose(false)即析構(gòu)函數(shù),負責自身非托管資源。如果沒有這部分可以不寫析構(gòu)函數(shù)。
5.dispose的實現(xiàn)方式要規(guī)范。最終dispose要顯式調(diào)用!
?
規(guī)范的dispose該注意哪些,這里補充一下:
private bool disposedValue = false; // 要檢測冗余調(diào)用protected virtual void Dispose(bool disposing){if (!disposedValue){if (disposing){// TODO: 釋放托管狀態(tài)(托管對象)。//這里應(yīng)該包含成員對象的dispose//大部分被包裝的資源的處理過程都寫在這里,比如退出過程:先保存,然后關(guān)閉,等等//safehandle.Dispose();}// TODO: 釋放未托管的資源(未托管的對象)并在以下內(nèi)容中替代終結(jié)器。// TODO: 將大型字段設(shè)置為 null。//這里是自身管理的一些資源的釋放,比如通過c api調(diào)用的一些非托管資源app = null;disposedValue = true;}}//TODO: 僅當以上 Dispose(bool disposing) 擁有用于釋放未托管資源的代碼時才替代終結(jié)器。~Excel(){// 請勿更改此代碼。將清理代碼放入以上 Dispose(bool disposing) 中。Dispose(false);}// 添加此代碼以正確實現(xiàn)可處置模式。void IDisposable.Dispose(){// 請勿更改此代碼。將清理代碼放入以上 Dispose(bool disposing) 中。Dispose(true);// TODO: 如果在以上內(nèi)容中替代了終結(jié)器,則取消注釋以下行。//也就是有析構(gòu)函數(shù)就有下面這行代碼,表示顯式運行dispose時,GC不需要再運行析構(gòu)函數(shù),提高性能GC.SuppressFinalize(this);}?
轉(zhuǎn)載于:https://www.cnblogs.com/Nobel/p/5190395.html
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的safehandle 和析构函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: YTU 2586: 填空题B-字画鉴别
- 下一篇: 将CAGradientLayer当做ma