2011-10-18 59 views
11

我已經閱讀了很多關於C#中的finalizer和IDisposable。當我終於從這個終結者和IDisposable這個可怕的混亂中清醒過來時,突然之間,突然之間,出現了這個SafeHandle的事情。我的信念再次完全動搖。我該用什麼?C#使用IDisposable或SafeHandle?

+2

用於* what *,究竟是什麼? –

+0

使用什麼,確切地說。我不知道現在應該在什麼情況下使用哪一種看起來相似的結構。 –

+1

@HansPassant在閱讀關於如何實現IDisposable的MSDN文章時,Microsoft提供了兩個如何實現該選項的選項。一個是實現一個終結器,並推薦使用一個SafeHandle。這確實有點混亂和誤導,所以我可以很好地理解OP的問題。 URL:http://msdn.microsoft.com/en-us/en-en/library/fs2xkftw%28v=vs.110%29.aspx 該網站使聲音非常通用,所以我第一次嘗試讓我的妥善處理的鋼筆物件也採用了SafeHandle,但效率不高。 – Tom

回答

15

SafeHandle僅在處理Win32 Interop調用時有用。在Win32中,大部分事物都由「句柄」表示。這包括Windows,Mutexes等。因此,.NET SafeHandle使用一次性模式來確保Win32句柄被正確關閉。

因此,如果您使用Win32 Interop調用並獲取Win32句柄,請使用SafeHandle。對於你自己的物體,你會堅持使用IDisposable和終結器。

+0

但[IDisposable](https://msdn.microsoft.com/en-us/library/system.idisposable(v = vs.110).aspx)的整點是釋放*非託管*資源,不是它? 「你自己的對象」聽起來很模糊,因爲對象可以代表一個託管的*和*非託管對象,因爲你是開發者,既可以開發管理代碼,也可以從你的託管代碼中調用你的非託管代碼,你自己定義的「也是模糊的。 –

+0

@zespri - 如果您決定實施IDisposable,那意味着您正在維護類/對象(即它是您的)。如果它是來自第三方庫的對象,則無法實現IDisposable(即,它不是您的)。我不是指應該處理什麼,也不是在非託管代碼中實現IDisposable。 – CodeNaked

+0

但是,如果它是來自第三方(託管)庫的對象,那麼您無法實現'SafeHandle'?僅僅因爲你最初可能沒有直接掌握手柄的能見度呢?對不起,不是好鬥,只是想明白你的意思。 –

5

對於任何可以表示爲IntPtr的非託管資源,即Win32句柄,由非託管代碼分配的內存等,您都可以/應該使用SafeHandle。如果SafeHandle不合適,但仍需要處理非託管資源,請考慮製作自己的SafeHandle-like類,繼承CriticalFinalizerObject

在所有其他情況下(即處理管理資源)實現IDisposable。在大多數情況下,你不需要終結器,當調用終結器時,大多數託管資源將不可用,所以在那裏沒有任何事情可做。

2

在大多數情況下,我的建議是假裝沒有終結器這樣的事情,但是100%確定任何創建的IDisposable對象都會被銷燬。即使終結器是以最佳方式寫入100%,那麼正確處理其一半對象並讓終結器處理另一半的代碼將不如代碼正確處理所有對象並且不使用終結器。儘管通常不會運行的終結器對性能的影響確實不是太糟糕,但終結器難以正確編寫,如果他們的代碼或代碼消耗的不完美,它們會導致Heisenbugs。此外,成功實現終結器通常需要創建一個或多個WeakHandles,其唯一目的是支持終結。

也許最終確定的安全網是值得的成本,但成本可以相當大,安全網不如人們可能想要的那樣可靠。